<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xml:lang="en-US">
  <title>BigBinary Blog: React Native</title>
  <subtitle>Deep technical writing on Ruby on Rails, performance, scaling, monitoring and engineering.</subtitle>
  <link rel="self" type="application/atom+xml" href="https://www.bigbinary.com/blog/categories/react-native/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/categories/react-native"/>
  <id>https://www.bigbinary.com/blog/categories/react-native</id>
  <updated>2023-03-13T00:00:00.000Z</updated>
  <author>
    <name>BigBinary</name>
    <uri>https://www.bigbinary.com/</uri>
  </author>
  <icon>https://www.bigbinary.com/favicon.ico</icon>
  <logo>https://www.bigbinary.com/images/bigbinary_square_big_logo.png</logo>
  <rights>Copyright 2023 Big Binary LLC</rights>
  <generator uri="https://nextjs.org">Next.js</generator>
  <entry>
      <title type="text"><![CDATA[Running React Native animations on the UI thread]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/running-react-native-dependent-animations-on-ui-thread-using-reanimated"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/running-react-native-dependent-animations-on-ui-thread-using-reanimated.png"/>
      <id>https://www.bigbinary.com/blog/running-react-native-dependent-animations-on-ui-thread-using-reanimated</id>
      <published>2023-03-13T00:00:00.000Z</published>
      <updated>2023-03-13T00:00:00.000Z</updated>
      <author>
        <name>Sangamesh Somawar</name>
        <uri>https://www.bigbinary.com/blog/authors/sangameshsomawar</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/running-react-native-dependent-animations-on-ui-thread-using-reanimated.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Learn how to run dependent animations on the UI thread to optimize and improve the performance with React Native Reanimated library]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/running-react-native-dependent-animations-on-ui-thread-using-reanimated"><![CDATA[<p><img src="https://user-images.githubusercontent.com/93119254/222339128-047c3afe-543f-48a0-9420-a8c6969a156c.gif" alt="Slider"></p>
<p>Here we have a slider. When the user slides the slider, the loader needs to show
how much is loaded. We want to animate the loader component when the slider
moves. In other words, the loader animation is &quot;dependent&quot; on the slider
animation.</p>
<p>This is an example of <em>Dependent Animations</em> on the UI thread. <em>Dependent
Animation</em> is when one view is animated based on another element.</p>
<p>first we need a gesture handler to detect the slider events. Then, based on the
slider events we need to animate the progress ofthe  loader component.</p>
<h3>Building gesture handler to detect the slider events</h3>
<pre><code class="language-jsx">const [width, setWidth] = useState(200);
const x = useSharedValue(0);

const gestureHandler = useAnimatedGestureHandler({
  onStart: (event, ctx) =&gt; {
    x.value = event.absoluteX;
  },
  onActive: (event, ctx) =&gt; {
    x.value = event.absoluteX;
    // We need to calculate `progress` here based on the slider position.
  },
});

const animatedStyle = useAnimatedStyle(() =&gt; {
  return {
    transform: [
      {
        translateX: x.value,
      },
    ],
  };
});

return (
  &lt;PanGestureHandler onGestureEvent={gestureHandler}&gt;
    &lt;Animated.View style={[{ height: 20 }]}&gt;
      &lt;Animated.View
        pointerEvents=&quot;none&quot;
        style={[
          {
            backgroundColor: &quot;blue&quot;,
            height: 20,
            width: 20,
            borderRadius: 10,
          },
          animatedStyle,
        ]}
      /&gt;
      &lt;View
        pointerEvents=&quot;none&quot;
        style={{
          backgroundColor: &quot;black&quot;,
          height: 2,
          width: &quot;100%&quot;,
          position: &quot;absolute&quot;,
          top: 10,
        }}
      /&gt;
    &lt;/Animated.View&gt;
  &lt;/PanGestureHandler&gt;
);
</code></pre>
<p><strong>Loader component:</strong></p>
<pre><code class="language-jsx">&lt;View style={{ height: 20, marginTop: 10 }}&gt;
  &lt;Lottie
    style={{
      alignSelf: &quot;center&quot;,
      width: &quot;100%&quot;,
    }}
    progress={&quot;Calculated `progress` based on slider position.&quot;}
    source={require(&quot;./progress&quot;)}
    autoPlay={false}
    loop={false}
  /&gt;
&lt;/View&gt;
</code></pre>
<h3>Animate the loader based on the slider position</h3>
<p>Before we move further, let's understand the difference between UI Thread and JS
Thread. The UI Thread handles rendering and gestures of Android and iOS views,
whereas the JS Thread takes care of all the logic of the React Native
application.</p>
<video width="320" height="240" controls muted>
  <source src="https://user-images.githubusercontent.com/93119254/199667917-fa5e172e-6b42-481a-abb4-34040179cef7.mov">
</video>
<p>We have two approaches for animating the loader.</p>
<p>In the first approach, when the slider moves, we can store the <code>progress</code> in
react state and pass it to <a href="https://lottiefiles.com/">Lottie animation</a>. With
this approach, the entire component rerenders on setting the <code>progress</code>.</p>
<pre><code class="language-jsx">const [progress, setProgress] = useState(0);
const gestureHandler = useAnimatedGestureHandler({
  onStart: (event, ctx) =&gt; {
    x.value = event.absoluteX;
  },
  onActive: (event, ctx) =&gt; {
    x.value = event.absoluteX;
    runOnJS(setProgress)(x.value / width);
  },
});

&lt;Lottie
  style={{
    alignSelf: &quot;center&quot;,
    width: &quot;100%&quot;,
  }}
  progress={progress}
  source={require(&quot;./progress&quot;)}
  autoPlay={false}
  loop={false}
/&gt;;
</code></pre>
<p>In the second approach, when the slider moves, we can calculate <code>progress</code> and
pass it to the loader component via the
<a href="https://docs.swmansion.com/react-native-reanimated/docs/api/hooks/useAnimatedProps/"><code>useAnimatedProps</code></a>.
In this way, the <code>progress</code> gets calculated on the UI thread itself. Hence it
avoids rerenders.</p>
<pre><code class="language-jsx">const LottieAnimated = Animated.createAnimatedComponent(Lottie);
const [progress, setProgress] = useState(0);
const lottieAnimatedProps = useAnimatedProps(() =&gt; progress: x.value / width);
const gestureHandler = useAnimatedGestureHandler({
  onStart: (event, ctx) =&gt; {
    x.value = event.absoluteX;
  },
  onActive: (event, ctx) =&gt; {
    x.value = event.absoluteX;
  },
});

&lt;LottieAnimated
  style={{
    alignSelf: &quot;center&quot;,
    width: &quot;100%&quot;,
  }}
  animatedProps={lottieAnimatedProps}
  source={require(&quot;./progress&quot;)}
  autoPlay={false}
  loop={false}
/&gt;;
</code></pre>
<h3>Conclusion</h3>
<p>With the first approach, whenever the slider moves, the UI thread will pass the
gesture event to the JS thread to store the <code>progress</code> value in react state, and
when the <code>progress</code> value changes in the JS thread, it causes a re-render. This
approach creates a lot of traffic over
<a href="https://reactnative.dev/architecture/threading-model">Communication Bridge</a>
because of the message exchange between UI and JS threads.</p>
<p>So we should prefer the second approach to run any calculations on the UI thread
instead of the JS thread. Here is the entire code for reference:</p>
<pre><code class="language-jsx">let approach1ReRenderCount1 = 0;
const Approach1: () =&gt; Node = () =&gt; {
  const [width, setWidth] = useState(1);
  const x = useSharedValue(0);

  const [progress, setProgress] = useState(0);
  const gestureHandler = useAnimatedGestureHandler({
    onStart: (event, ctx) =&gt; {
      x.value = event.absoluteX;
    },
    onActive: (event, ctx) =&gt; {
      x.value = event.absoluteX;
      runOnJS(setProgress)(x.value / width);
    },
  });

  const animatedStyle = useAnimatedStyle(() =&gt; {
    return {
      transform: [
        {
          translateX: x.value,
        },
      ],
    };
  });

  return (
    &lt;SafeAreaView&gt;
      &lt;View
        style={{
          height: 150,
          paddingHorizontal: 20,
          borderWidth: 1,
          margin: 10,
          justifyContent: &quot;center&quot;,
        }}
        onLayout={({
          nativeEvent: {
            layout: { width },
          },
        }) =&gt; {
          setWidth(width);
        }}
      &gt;
        &lt;Text style={{ fontSize: 20, paddingBottom: 10 }}&gt;Approach 1&lt;/Text&gt;
        &lt;Text style={{ fontSize: 20 }}&gt;
          Rerender Count : {approach1ReRenderCount1++}
        &lt;/Text&gt;

        &lt;View style={{ height: 20, marginTop: 10 }}&gt;
          &lt;LottieAnimated
            style={{
              alignSelf: &quot;center&quot;,
              width: &quot;100%&quot;,
            }}
            progress={progress}
            source={require(&quot;./progress&quot;)}
            autoPlay={false}
            loop={false}
          /&gt;
        &lt;/View&gt;
        &lt;PanGestureHandler onGestureEvent={gestureHandler}&gt;
          &lt;Animated.View style={[{ height: 20 }]}&gt;
            &lt;Animated.View
              style={[
                {
                  backgroundColor: &quot;blue&quot;,
                  height: 20,
                  width: 20,
                  borderRadius: 10,
                },
                animatedStyle,
              ]}
            /&gt;
            &lt;View
              style={{
                backgroundColor: &quot;black&quot;,
                height: 2,
                width: &quot;100%&quot;,
                position: &quot;absolute&quot;,
                top: 10,
              }}
            /&gt;
          &lt;/Animated.View&gt;
        &lt;/PanGestureHandler&gt;
      &lt;/View&gt;
    &lt;/SafeAreaView&gt;
  );
};

const LottieAnimated = Animated.createAnimatedComponent(Lottie);
let approach2ReRenderCount = 0;
const Approach2: () =&gt; Node = () =&gt; {
  const [width, setWidth] = useState(1);
  const x = useSharedValue(0);

  const lottieAnimatedProps = useAnimatedProps(() =&gt; progress: x.value / width);

  const gestureHandler = useAnimatedGestureHandler({
    onStart: (event, ctx) =&gt; {
      x.value = event.absoluteX;
    },
    onActive: (event, ctx) =&gt; {
      x.value = event.absoluteX;
    },
  });

  const animatedStyle = useAnimatedStyle(() =&gt; {
    return {
      transform: [
        {
          translateX: x.value,
        },
      ],
    };
  });

  return (
    &lt;SafeAreaView&gt;
      &lt;View
        style={{
          height: 150,
          paddingHorizontal: 20,
          borderWidth: 1,
          margin: 10,
          justifyContent: &quot;center&quot;,
        }}
        onLayout={({
          nativeEvent: {
            layout: { width },
          },
        }) =&gt; {
          setWidth(width);
        }}
      &gt;
        &lt;Text style={{ fontSize: 20, paddingBottom: 10 }}&gt; Approach 2&lt;/Text&gt;
        &lt;Text style={{ fontSize: 20 }}&gt;
          Rerender Count : {approach2ReRenderCount++}
        &lt;/Text&gt;
        &lt;View style={{ height: 20, marginTop: 10 }}&gt;
          &lt;LottieAnimated
            animatedProps={lottieAnimatedProps}
            style={{
              alignSelf: &quot;center&quot;,
              width: &quot;100%&quot;,
            }}
            source={require(&quot;./progress&quot;)}
            autoPlay={false}
            loop={false}
          /&gt;
        &lt;/View&gt;
        &lt;PanGestureHandler onGestureEvent={gestureHandler}&gt;
          &lt;Animated.View style={[{ height: 20 }]}&gt;
            &lt;Animated.View
              pointerEvents=&quot;none&quot;
              style={[
                {
                  backgroundColor: &quot;blue&quot;,
                  height: 20,
                  width: 20,
                  borderRadius: 10,
                },
                animatedStyle,
              ]}
            /&gt;
            &lt;View
              pointerEvents=&quot;none&quot;
              style={{
                backgroundColor: &quot;black&quot;,
                height: 2,
                width: &quot;100%&quot;,
                position: &quot;absolute&quot;,
                top: 10,
              }}
            /&gt;
          &lt;/Animated.View&gt;
        &lt;/PanGestureHandler&gt;
      &lt;/View&gt;
    &lt;/SafeAreaView&gt;
  );
};
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Removing the white screen before the Android splash screen]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/adding-splash-screen-in-react-native-cli-app"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/adding-splash-screen-in-react-native-cli-app.png"/>
      <id>https://www.bigbinary.com/blog/adding-splash-screen-in-react-native-cli-app</id>
      <published>2022-07-28T00:00:00.000Z</published>
      <updated>2022-07-28T00:00:00.000Z</updated>
      <author>
        <name>Kamolesh Mondal</name>
        <uri>https://www.bigbinary.com/blog/authors/kamoleshmondal</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/adding-splash-screen-in-react-native-cli-app.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[A walk-through on the correct way to add a splash screen to a react-native cli application.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/adding-splash-screen-in-react-native-cli-app"><![CDATA[<p>In order to add a splash screen, we'll use the
<a href="https://www.npmjs.com/package/react-native-splash-screen">react-native-splash-screen</a>
package. While most of the job is done by following the installation steps,
there are some additional steps we need to follow for Android.</p>
<p>There's a concept known as the &quot;preview window&quot; in Android which serves a basic
purpose of faking a fast launch of an app when the app icon is clicked. While
preview window fakes fast launching, it shows an empty white screen until the
app has loaded. More info available in
<a href="https://www.tothenew.com/blog/disabling-the-preview-or-start-window-in-android/">this</a>
article.</p>
<p>The preview window can itself be disabled by adding the following line in the
<code>android/app/src/main/res/values/styles.xml</code> file.</p>
<pre><code class="language-xml">&lt;item name=&quot;android:windowDisablePreview&quot;&gt;true&lt;/item&gt;
</code></pre>
<p>However, disabling the preview window introduces an undesirable delay between
clicking on the app icon and the actual launching of the app.</p>
<p>We can get rid of the delay and the empty white screen by adding an additional
splash activity.</p>
<h2>Additional steps for Android</h2>
<ul>
<li>
<p>Create a background_splash.xml file with the same design you used in
<code>launch_screen.xml</code> during the installation above.</p>
</li>
<li>
<p>Place this new xml file inside the <code>android/app/src/main/res/drawable</code>
directory.</p>
</li>
<li>
<p>Create a new splash theme in the <code>android/app/src/main/res/values/styles.xml</code>
file by adding the following snippet.</p>
<pre><code class="language-xml">&lt;style name=&quot;SplashTheme&quot; parent=&quot;Theme.AppCompat.Light.NoActionBar&quot;&gt;
    &lt;item name=&quot;android:windowBackground&quot;&gt;@drawable/background_splash&lt;/item&gt;
&lt;/style&gt;
</code></pre>
</li>
<li>
<p>Create a new splash activity to call the main activity, and add the following
code in it.</p>
<pre><code class="language-java">package com.example;

import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}
</code></pre>
</li>
<li>
<p>Finally, we will call this activity first on launch with the splash theme we
created above.</p>
</li>
<li>
<p>Add the new activity in AndroidManifest.xml.</p>
<pre><code class="language-xml">&lt;activity android:name=&quot;.SplashActivity&quot; android:label=&quot;@string/app_name&quot; android:launchMode=&quot;singleTask&quot; android:theme=&quot;@style/SplashTheme&quot;&gt;
  &lt;intent-filter&gt;
    &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
    &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
  &lt;/intent-filter&gt;
&lt;/activity&gt;
</code></pre>
</li>
<li>
<p>The intent-filter tag, with its &quot;MAIN&quot; action and &quot;LAUNCHER&quot; category
children, allows us to call this new activity first on launch. It's usually
found in the main activity by default, so we have to remove them entirely from
there, leaving them exclusively in <code>SplashActivity</code>.</p>
</li>
</ul>
<p>Once we've done all this, we can rebuild the app and run it with
<code>npx react-native run-android</code> to see the splashscreen we created.</p>
<p>The app should now launch quickly with no empty white screen on startup.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Playing videos in React Native]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/playing-videos-in-react-native-using-cloudinary"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/playing-videos-in-react-native-using-cloudinary.png"/>
      <id>https://www.bigbinary.com/blog/playing-videos-in-react-native-using-cloudinary</id>
      <published>2021-09-14T00:00:00.000Z</published>
      <updated>2021-09-14T00:00:00.000Z</updated>
      <author>
        <name>Chirag Bhaiji</name>
        <uri>https://www.bigbinary.com/blog/authors/chiragb</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/playing-videos-in-react-native-using-cloudinary.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[These days, a large number of mobile apps allow users to upload videos and play those videos efficiently. While building these features in a React Native app, we ran into some challenges. In this...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/playing-videos-in-react-native-using-cloudinary"><![CDATA[<p>These days, a large number of mobile apps allow users to upload videos and play
those videos efficiently. While building these features in a React Native app, we
ran into some challenges. In this blog, we will discuss those challenges and the
solutions.</p>
<h2>Where to host the videos</h2>
<p>Since we are dealing with video,s we need a service that will store, host, encode
and be a CDN. After looking at various service providers, we decided to go with
<a href="https://cloudinary.com/">Cloudinary</a>. Cloudinary is a service provider with an
end-to-end image/video-management solution for web and mobile applications,
covering everything from <strong><em>uploads, storage, manipulations, optimizations to
delivery</em></strong> with a fast content delivery network (<strong><em>CDN</em></strong>).</p>
<h3>Setting up react-native-video player</h3>
<p>We decided to use
<a href="https://github.com/react-native-video/react-native-video">react-native-video</a>
<code>v5.1.1</code> for playing videos in React Native application. Here is the
<a href="https://github.com/react-native-video/react-native-video#readme">guide</a> to set
up the video player.</p>
<pre><code class="language-jsx">import Video from &quot;react-native-video&quot;;

const Player = ({ uri }) =&gt; {
  return (
    &lt;SafeAreaView style={styles.container}&gt;
      &lt;Video
        style={styles.player}
        source={{ uri }}
        controls
        resizeMode=&quot;contain&quot;
      /&gt;
    &lt;/SafeAreaView&gt;
  );
};
</code></pre>
<p>The above code snippet works perfectly on iOS but not on Android. On Android, we
faced a
<a href="https://github.com/react-native-video/react-native-video/issues/1032">known issue</a>
where the video doesn't play, but the audio plays with significant delay. This
issue can be resolved by setting
<a href="https://developer.android.com/guide/topics/media/exoplayer">exoplayer</a> as the
default player for Android in <code>react-native.config.js</code> in the root directory of
the project.</p>
<pre><code class="language-js">module.exports = {
  dependencies: {
    &quot;react-native-video&quot;: {
      platforms: {
        android: {
          sourceDir: &quot;../node_modules/react-native-video/android-exoplayer&quot;,
        },
      },
    },
  },
};
</code></pre>
<h3>Setting up Cloudinary</h3>
<p>A Cloudinary account is required before proceeding. Once the account is
ready, following are the steps to enable unsigned upload for the account.</p>
<ul>
<li>Go to the <em>Settings</em> of Cloudinary.</li>
<li>Select the <em>Upload</em> tab.</li>
<li>Search for <em>Upload presets</em> section.</li>
<li>Click on <em>Enable unsigned uploading</em>.</li>
</ul>
<p>This generates an upload preset with a random name, which will be required for
the unsigned upload.</p>
<h2>Setting up Client for Upload</h2>
<h3>Selecting Video from the gallery</h3>
<p>We decided to use
<a href="https://github.com/ivpusic/react-native-image-crop-picker">react-native-image-crop-picker</a>
<code>v0.36.2</code> library to select the video from the gallery. Here is the
<a href="https://github.com/ivpusic/react-native-image-crop-picker#readme">guide</a> for
setting it up.</p>
<pre><code class="language-jsx">import ImagePicker from &quot;react-native-image-crop-picker&quot;;

const selectVideo = ({ setVideoToUpload }) =&gt; {
  ImagePicker.openPicker({ mediaType: &quot;video&quot; })
    .then(setVideoToUpload)
    .catch(console.error);
};
</code></pre>
<h3>Uploading Video</h3>
<pre><code class="language-js">// Cloud Name: Found on the Dashboard of Cloudinary.
const URL = &quot;https://api.cloudinary.com/v1_1/&lt;CLOUD_NAME&gt;/video/upload&quot;;
// Random Name: Generated After Enabling The Unsigned Uploading.
const UPLOAD_PRESET = &quot;&lt;UPLOAD_PRESET_FOR_UNSIGNED_UPLOAD&gt;&quot;;

const uploadVideo = (fileInfo, onSuccess, onError) =&gt; {
  const { name, uri, type } = fileInfo;
  let formData = new FormData();

  if (uri) {
    formData.append(&quot;file&quot;, { name, uri, type });
    formData.append(&quot;upload_preset&quot;, UPLOAD_PRESET);
  }

  axios
    .post(URL, formData, {
      headers: { &quot;Content-Type&quot;: &quot;multipart/form-data&quot; },
    })
    .then(res =&gt; onSuccess(res.data))
    .catch(error =&gt; onError(error));
};

export default { uploadVideo };
</code></pre>
<h3>Fetching Videos on client</h3>
<pre><code class="language-js">import base64 from &quot;base-64&quot;;

// API Key and Secret: Found on the Dashboard of Cloudinary.
const API_KEY = &quot;&lt;API_KEY&gt;&quot;;
const API_SECRET = &quot;&lt;API_SECRET&gt;&quot;;

const URL = `https://api.cloudinary.com/v1_1/&lt;CLOUD_NAME&gt;/resources/video`;

const getVideos = (onRes, onError) =&gt; {
  axios
    .get(URL, {
      headers: {
        Authorization: base64.encode(`${API_KEY}:${API_SECRET}`),
      },
    })
    .then(res =&gt; onRes(res.data.resources))
    .catch(error =&gt; onError(error));
};

export default { getVideos };
</code></pre>
<p>Response:</p>
<pre><code class="language-json">{
  &quot;resources&quot;: [
    {
      &quot;asset_id&quot;: &quot;475675ddd87cb3bb380415736ed1e3dc&quot;,
      &quot;public_id&quot;: &quot;samples/elephants&quot;,
      &quot;format&quot;: &quot;mp4&quot;,
      &quot;version&quot;: 1628233788,
      &quot;resource_type&quot;: &quot;video&quot;,
      &quot;type&quot;: &quot;upload&quot;,
      &quot;created_at&quot;: &quot;2021-08-06T07:09:48Z&quot;,
      &quot;bytes&quot;: 38855178,
      &quot;width&quot;: 1920,
      &quot;height&quot;: 1080,
      &quot;access_mode&quot;: &quot;public&quot;,
      &quot;url&quot;: &quot;http://res.cloudinary.com/do77lourv/video/upload/v1628233788/samples/elephants.mp4&quot;,
      &quot;secure_url&quot;: &quot;https://res.cloudinary.com/do77lourv/video/upload/v1628233788/samples/elephants.mp4&quot;
    }
    //...
  ]
}
</code></pre>
<h3>Transforming uploaded videos for faster delivery</h3>
<p>One way to play a video is to first completely download the video on the
client's device and then play it locally. The biggest drawback of this approach
is that it could take a long time before the video is fully downloaded and till
then the device is not playing anything at all. This strategy also requires a
sophisticated algorithm to manage memory.</p>
<p>Another solution is to use
<a href="https://en.wikipedia.org/wiki/Adaptive_bitrate_streaming">Adaptive Bitrate Streaming</a>(ABS)
for playing videos. As the name suggests in this case, the video is being
streamed. It is one of the most efficient ways to deliver videos based on the
client's internet bandwidth and device capabilities.</p>
<p>To generate ABS, we add an eager transformation to the upload preset we created
while setting up the Cloudinary account earlier.</p>
<p>An eager transformation runs automatically for all the videos uploaded using the
upload preset which has the transformation added.</p>
<h3>Setup Transformation</h3>
<p>Here are the steps for adding an eager transformation to the upload preset.</p>
<ul>
<li>Go to the upload preset that was generated when the unsigned upload was
enabled while setting up Cloudinary in the earlier section.</li>
<li>Click on edit.</li>
<li>Go to the Upload Manipulations section.</li>
<li>Click on <code>Add Eager Transformation</code> to open the Edit Transaction window.</li>
<li>Open the <code>Format</code> dropdown under the <code>Format &amp; shape</code> section and select
<code>M3U8 Playlist (HLS)</code>.</li>
<li>Select any streaming profile from the dropdown under the <code>More options</code>. Any
profile matching your maximum required quality can be selected here.</li>
</ul>
<p>Next upload a video with the same preset, trigger the transformation to generate
The <code>M3U8</code> format, which is the one we need for playing the videos as streams.</p>
<h3>Consuming video streams</h3>
<p>To play streams, the <code>type</code> property must be provided to the
<code>react-native-video</code>'s source prop. In this case, <code>type</code> will be <code>m3u8</code>. Also,
the URI needs to be updated with this same extension.</p>
<pre><code class="language-diff">- source={{ uri }}
+ source={{ uri: uri.replace(`.${format}`, '.m3u8'), type: 'm3u8'}}
</code></pre>
<h3>Conclusion</h3>
<p>Once all the above mentioned steps were performed, we were able to upload
and stream videos on both iOS and Android without any issues.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Handling environment specific configurations in React Native]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/handling-environment-specific-configurations-in-react-native"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/handling-environment-specific-configurations-in-react-native.png"/>
      <id>https://www.bigbinary.com/blog/handling-environment-specific-configurations-in-react-native</id>
      <published>2021-04-27T00:00:00.000Z</published>
      <updated>2021-04-27T00:00:00.000Z</updated>
      <author>
        <name>Sourav Kumar</name>
        <uri>https://www.bigbinary.com/blog/authors/souravkumar</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/handling-environment-specific-configurations-in-react-native.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Many modern-day applications now go through different stages of the product cycle such as development, staging, production etc. Having different environment variables for each environment will make...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/handling-environment-specific-configurations-in-react-native"><![CDATA[<p>Many modern-day applications now go through different stages of the product
cycle such as development, staging, production etc.</p>
<p>Having different environment variables for each environment will make it a lot
easier to manage any application. This article is intended to share one solution
to address this problem in React Native. We will be using a library called
<a href="https://github.com/luggit/react-native-config">react-native-config</a> for this
purpose; you can also try
<a href="https://github.com/zetachang/react-native-dotenv">react-native-dotenv</a>.</p>
<p>We will be focusing on having three different bundles containing configuration
files for development, staging and production environments.</p>
<h2>Installing react-native-config</h2>
<p>Install the package:</p>
<pre><code class="language-bash">yarn add react-native-config
</code></pre>
<p>For iOS also run <code>pod install</code> after package is installed.</p>
<h2>Setup for Android</h2>
<p>Add below line of code to <code>android/app/build.gradle</code> to apply plugin.</p>
<pre><code class="language-diff">apply plugin: &quot;com.android.application&quot;
+ apply from: project(':react-native-config').projectDir.getPath() + &quot;/dotenv.gradle&quot;
</code></pre>
<p>Create three files in root folder of the project <code>.env.development</code>,
<code>.env.staging</code> &amp; <code>.env.production</code> which will contain our environment variables.</p>
<pre><code class="language-text">// .env.development
API_URL=https://myapi.development.com

// .env.staging
API_URL=https://myapi.staging.com

// .env.production
API_URL=https://myapi.com
</code></pre>
<p>Now we need to define <code>envConfigFiles</code> in <code>build.gradle</code> associating builds with
env files. To achieve this, add the below code before the <code>apply from</code> call,
and be sure to leave the build cases in lowercase.</p>
<pre><code class="language-diff">+ project.ext.envConfigFiles = [
+   productiondebug: &quot;.env.production&quot;,
+   productionrelease: &quot;.env.production&quot;,
+   developmentrelease: &quot;.env.development&quot;,
+   developmentdebug: &quot;.env.development&quot;,
+   stagingrelease: &quot;.env.staging&quot;,
+   stagingdebug: &quot;.env.staging&quot;
+ ]

apply from: project(':react-native-config').projectDir.getPath() + &quot;/dotenv.gradle&quot;

</code></pre>
<p>Next, add <code>productFlavors</code> in <code>build.gradle</code>, just below <code>buildTypes</code>.</p>
<pre><code class="language-text">flavorDimensions &quot;default&quot;
  productFlavors {
    production {}
    staging {
      // We can have build-specific configurations here. Like using applicationIdSuffix to create different package name (ex. &quot;.staging&quot;)
    }
    development {}
  }
</code></pre>
<p>Names should match based on <code>productFlavors</code>, so <code>productiondebug</code> will match
<code>debug</code> in this case and generate debug build of App with configuration from
<code>.env.production</code>.</p>
<p>Also add <code>matchingFallbacks</code> in <code>buildTypes</code> as shown below:</p>
<pre><code class="language-diff">buildTypes {
  debug {
    signingConfig signingConfigs.debug
+   matchingFallbacks = ['debug', 'release']
  }
  release {
    signingConfig signingConfigs.debug
    minifyEnabled enableProguardInReleaseBuilds
    proguardFiles getDefaultProguardFil  (&quot;proguard-android.txt&quot;), &quot;proguard-rules  pro&quot;
  }
 }
</code></pre>
<p>Add the below scripts to <code>scripts</code> in the <code>package.json</code> file.</p>
<pre><code class="language-javascript">&quot;android:staging&quot;: &quot;react-native run-android --variant=stagingdebug&quot;,
&quot;android:staging-release&quot;: &quot;react-native run-android --variant=stagingrelease&quot;,
&quot;android:dev&quot;: &quot;react-native run-android --variant=developmentdebug&quot;,
&quot;android:dev-release&quot;: &quot;react-native run-android --variant=developmentrelease&quot;,
&quot;android:prod&quot;: &quot;react-native run-android --variant=productiondebug&quot;,
&quot;android:prod-release&quot;: &quot;react-native run-android --variant=productionrelease&quot;,
</code></pre>
<p>Now, to have a debug build with staging environment, run:</p>
<pre><code class="language-bash">yarn android:staging
</code></pre>
<p>Or, to have a release build with staging environment, run:</p>
<pre><code class="language-bash">yarn android:staging-release
</code></pre>
<h2>Setup for iOS</h2>
<p>In iOS we will create three new schemes <code>TestAppDevelopment</code>, <code>TestAppStaging</code> &amp;
<code>TestAppProduction</code> containing configuration files for development, staging and
production environments respectively.</p>
<p>To create schemes, open the project in xcode &amp; do the following:</p>
<p>In the Xcode menu, go to Product &gt; Scheme &gt; Edit Scheme.</p>
<p>Click Duplicate Scheme on the bottom and name it <code>TestAppDevelopment</code> and check
the <code>shared</code> checkbox.</p>
<p>We will repeat the above steps two more times (for <code>TestAppStaging</code> &amp;
<code>TestAppProduction</code>).</p>
<p>Now edit the newly generated scheme. Expand &quot;Build&quot; settings and click
&quot;Pre-actions&quot;, and under the plus sign select &quot;New Run Script Action&quot;. Select
project from the <code>Provide build settings from</code> dropdown.</p>
<p>Where it says &quot;Type a script or drag a script file&quot;, type:</p>
<pre><code class="language-bash">cp &quot;${PROJECT_DIR}/../.env.staging&quot; &quot;${PROJECT_DIR}/../.env&quot;  # replace .env.staging for your file
</code></pre>
<p>Add the below scripts to <code>scripts</code> in the <code>package.json</code> file.</p>
<pre><code class="language-javascript">&quot;ios:dev&quot;: &quot;react-native run-ios --scheme 'TestAppDevelopment'&quot;,
&quot;ios:prod&quot;: &quot;react-native run-ios --scheme 'TestAppProduction'&quot;,
&quot;ios:staging&quot;: &quot;react-native run-ios --scheme 'TestAppStaging'&quot;,
</code></pre>
<p>Now, to have a build with staging environment, run:</p>
<pre><code class="language-bash">yarn ios:staging
</code></pre>
<p>And it will run the application with staging configuration.</p>
<h2>Accessing environment variables</h2>
<p>Once the setup is complete, we can access the variables as shown below:</p>
<pre><code class="language-javascript">import Config from &quot;react-native-config&quot;;
Config.API_URL;
//`https://myapi.staging.com`
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Handling authentication state in React Native]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/handling-authentication-state-in-react-native"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/handling-authentication-state-in-react-native.png"/>
      <id>https://www.bigbinary.com/blog/handling-authentication-state-in-react-native</id>
      <published>2021-04-06T00:00:00.000Z</published>
      <updated>2021-04-06T00:00:00.000Z</updated>
      <author>
        <name>Ajay Sivan</name>
        <uri>https://www.bigbinary.com/blog/authors/ajayesivan</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/handling-authentication-state-in-react-native.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Authentication flow is an essential part of any modern mobile application. In this article, we will see how to store and manage the authentication state in React Native. Storing auth data Let's...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/handling-authentication-state-in-react-native"><![CDATA[<p>Authentication flow is an essential part of any modern mobile application. In
this article, we will see how to store and manage the authentication state in
React Native.</p>
<h2>Storing auth data</h2>
<p>Let's consider a basic scenario where we use a phone number and authentication
token for verifying API requests. Here we need to persist both the phone number
and authentication token. For storing these data we can use AsyncStorage, which
is a key-value data store commonly used to persist data locally in React Native.
Even though we are storing two different values, we will always access them
together and hence we can avoid multiple AsyncStorage calls by storing them as a
single key-value pair.</p>
<pre><code class="language-javascript">const auth = {
  phone: PHONE_NUMBER, // User's phone number
  token: AUTH_TOKEN, // Authentication token
};

AsyncStorage.setItem(&quot;auth&quot;, JSON.stringify(auth));
// AsyncStorage supports only string values - so we have to serialize our object.
</code></pre>
<p>After storing the data we can use the <code>AsyncStorage.getItem()</code> API to retrieve
it.</p>
<h3>Things to keep in mind while using AsyncStorage</h3>
<p>It should be clear from the name that AsyncStorage calls are asynchronous so
consider the following while using it.</p>
<ul>
<li>
<p>Avoid unnecessary AsyncStorage calls - Async calls will take time and may
affect user experience.</p>
</li>
<li>
<p>Reuse data once fetched - Use higher-level state or central state management
like Context, Redux etc to manage data used in multiple places.</p>
</li>
<li>
<p>Asynchronous calls might fail and we should handle exceptions properly.</p>
</li>
<li>
<p>In Android, AsyncStorage has a 6MB hard limit. You can change it by setting
<code>AsyncStorage_db_size_in_MB</code> value in <code>gradle.properties</code> file.</p>
</li>
<li>
<p>AsyncStorage uses SQLite so beware of
<a href="https://www.sqlite.org/limits.html">SQLite limits</a>.</p>
</li>
</ul>
<h2>Manage auth state globally with Context API</h2>
<p>In many apps we would use the current authentication state to display
appropriate content based on auth state, user type etc., so it's always good to
put it in a centrally accessible place. We can use a central state management
library like Redux or Context API. In this example we will use the built-in
Context API.</p>
<p>Let's create an AuthContext and store all auth data in the Provider state by
fetching it from AsyncStorage. We will also an API to update the data in state &amp;
AsyncStorage.</p>
<h3>AuthContext</h3>
<pre><code class="language-javascript">// Create a context
const AuthContext = createContext({});

const AuthProvider = ({ children }) =&gt; {
  const [auth, setAuthState] = useState(initialState);

  // Get current auth state from AsyncStorage
  const getAuthState = async () =&gt; {
    try {
      const authDataString = await AsyncStorage.getItem(&quot;auth&quot;);
      const authData = JSON.parse(authDataString || {});
      // Configure axios headers
      configureAxiosHeaders(authData.token, authData.phone);
      setAuthState(authData);
    } catch (err) {
      setAuthState({});
    }
  };

  // Update AsyncStorage &amp; context state
  const setAuth = async (auth) =&gt; {
    try {
      await AsyncStorage.setItem(&quot;auth&quot;, JSON.stringify(auth));
      // Configure axios headers
      configureAxiosHeaders(auth.token, auth.phone);
      setAuthState(auth);
    } catch (error) {
      Promise.reject(error);
    }
  };

  useEffect(() =&gt; {
    getAuthState();
  }, []);

  return (
    &lt;AuthContext.Provider value={{ auth, setAuth }}&gt;
      {children}
    &lt;/AuthContext.Provider&gt;
  );
};

export { AuthContext, AuthProvider };
</code></pre>
<p>When using axios we can configure the default auth headers and they will be used
for all API requests. In case you are not using axios you can still get auth
values from the context.</p>
<pre><code class="language-javascript">const configureAxiosHeaders = (token, phone) =&gt; {
  axios.defaults.headers[&quot;X-Auth-Token&quot;] = token;
  axios.defaults.headers[&quot;X-Auth-Phone&quot;] = phone;
};
</code></pre>
<p>Now we can wrap our root component with <code>AuthProvider</code> and use the
<code>useContext()</code> API in any component to access the auth state.</p>
<h2>Restricting routes(screens)</h2>
<p>Displaying appropriate screens and restricting access to screens based on the
auth state is a common use case. In this section, we will see how to display
Login/Signup screens if the user is not authenticated and a Home screen if the
user is already authenticated.</p>
<pre><code class="language-javascript">const App = () =&gt; {
  // Get auth state from context
  const { auth } = useContext(AuthContext);

  return (
    &lt;NavigationContainer&gt;
      &lt;Stack.Navigator&gt;
        {auth.token ? (
          &lt;Stack.Screen name=&quot;Home&quot; component={Home} /&gt;
        ) : (
          &lt;&gt;
            &lt;Stack.Screen name=&quot;Signup&quot; component={Signup} /&gt;
            &lt;Stack.Screen name=&quot;Login&quot; component={Login} /&gt;
          &lt;/&gt;
        )}
      &lt;/Stack.Navigator&gt;
    &lt;/NavigationContainer&gt;
  );
};
</code></pre>
<p>In the above snippet, we are conditionally rendering screens based on the auth
token rather than doing manual navigation using <code>navigate</code> function. This will
help us restrict access to screens and avoid accessing restricted screens when
navigating from code or using the system back button in android.</p>
<h3>Things to keep in mind while using react navigation</h3>
<ul>
<li>
<p>Try to keep all top-level StackNavigator screens in one place to avoid
unexpected behaviour.</p>
</li>
<li>
<p>Use conditional rendering to restrict screens.</p>
</li>
<li>
<p>Use <code>replace</code> instead of <code>navigate</code> when you want to remove the current screen
from the back stack.</p>
</li>
<li>
<p>Use constants for screen names instead of string literals.</p>
</li>
</ul>
<h2>Enhancements</h2>
<ul>
<li>
<p>Store additional pieces of information like user type, username etc in the
Auth context for easier access.</p>
</li>
<li>
<p>Improve AuthContext by using useReducer instead of useState.</p>
</li>
<li>
<p>Consider using state management libraries like Redux if you want to manage
lots of states globally.</p>
</li>
<li>
<p>Use a loader state to display a SplashScreen until we fetch the auth state
from AsyncStorage for the first time.</p>
</li>
</ul>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Higher Order Component to render spinner React Native]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/higher-order-component-for-rendering-spinner-in-react-native-app"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/higher-order-component-for-rendering-spinner-in-react-native-app.png"/>
      <id>https://www.bigbinary.com/blog/higher-order-component-for-rendering-spinner-in-react-native-app</id>
      <published>2017-11-15T00:00:00.000Z</published>
      <updated>2017-11-15T00:00:00.000Z</updated>
      <author>
        <name>Chirag Shah</name>
        <uri>https://www.bigbinary.com/blog/authors/chiraggshah</uri>
      </author>
      <category term="React Native"/>
      <category term="JavaScript"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/higher-order-component-for-rendering-spinner-in-react-native-app.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[How we wrote our own Higher Order Component for rendering spinner in react native app]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/higher-order-component-for-rendering-spinner-in-react-native-app"><![CDATA[<p>In one of our
<a href="https://bigbinary.com/blog/using-recompose-to-build-higher-order-components">previous blogs</a>,
we mentioned how
<a href="https://github.com/acdlite/recompose">recompose</a>
improves both
the readability
and the
maintainability
of the code.</p>
<p>We also saw
how <a href="https://github.com/acdlite/recompose/blob/master/docs/API.md#branch">branch</a>
and
<a href="https://github.com/acdlite/recompose/blob/master/docs/API.md#rendercomponent">renderComponent</a>
functions
from <code>recompose</code>
help us
in deciding
which component to render
based on a condition.</p>
<p>We can use the code from
<a href="https://github.com/acdlite/recompose/blob/master/docs/API.md#rendercomponent">renderComponent documentation</a>
to render a
spinner component when
the data is being fetched
in a ReactJS application.</p>
<h2>Initial Code</h2>
<pre><code class="language-javascript">// PatientsList.js

import React, { Component } from 'react';
import LoadingIndicator from './LoadingIndicator';

export default class PatientsList extends Component {

  state = {
    isLoading: true,
    patientsList: [],
  }

  componentDidMount() {
    api.getPatientsList().then(responseData =&gt; {
      this.setState({
        patientsList: responseData,
        isLoading: false,
      })
    })
  }

  render() {
    const { isLoading } = this.state;
    if (isLoading) {
      return &lt;LoadingIndicator isLoading={isLoading} /&gt;
    } else {
      return (
        &lt;ScrollView&gt;
          // Some header component
          // View rendering the patients
        &lt;/ScrollView&gt;
      )
    }
  }
</code></pre>
<p>In the above code,
when the PatientsList component mounts,
it fetches
the list of patients from the API.
During this time,
the <code>isLoading</code> state is <code>true</code>,
so we render
the <code>LoadingIndicator</code> component.</p>
<p>Once the API call
returns with the response,
we set
the <code>isLoading</code> state to <code>false</code>.
This renders
<code>ScrollView</code> component,
with our list of patients.</p>
<p>The above code works fine,
but
if our app has multiple screens,
which show
the loading indicator
and fetch data,
the above way
of handling it
becomes repetitive
and hard to maintain.</p>
<h2>Building a higher order component</h2>
<p>Here's where
Higher Order Components(HOC)
are very useful.
We can extract the logic
for the ability
to show the loading indicator
in a HOC.</p>
<pre><code class="language-javascript">// withSpinner.js

import React from &quot;react&quot;;
import { ScrollView } from &quot;react-native&quot;;
import LoadingIndicator from &quot;./LoadingIndicator&quot;;

const withSpinner = (Comp) =&gt; ({ isLoading, children, ...props }) =&gt; {
  if (isLoading) {
    return &lt;LoadingIndicator isLoading={isLoading} /&gt;;
  } else {
    return &lt;Comp {...props}&gt;{children}&lt;/Comp&gt;;
  }
};

export default withSpinner;
</code></pre>
<p>Here,
we created a HOC component
which accepts a component
and the <code>isLoading</code> prop.</p>
<p>If <code>isLoading</code> is true,
we show the <code>LoadingIndicator</code>.
If <code>isLoading</code> is false,
we show the supplied component
with its children,
and pass in the props.</p>
<p>Now,
we can use the above HOC
in our PatientsList.js file.
The supplied component
can be any React Native component
based on the use case.
Here in our case,
its a ScrollView.</p>
<pre><code class="language-javascript">// PatientsList.js

import { ScrollView } from 'react-native';
import withSpinner from './withSpinner';
const ScrollViewWithSpinner = withSpinner(ScrollView);

export default class PatientsList extends Component {

  state = {
    isLoading: true,
    patientsList: [],
  }

  componentDidMount() {
    api.getPatientsList().then(responseData =&gt; {
      this.setState({
        patientsList: responseData,
        isLoading: false,
      })
    })
  }

  render() {
    const { isLoading } = this.state;
    return(
      &lt;ScrollViewWithSpinner
        isLoading={isLoading}
        // other props
      &gt;
        // Some header component
        // View rendering the patients
      &lt;/ScrollViewWithSpinner&gt;
    )
  }
</code></pre>
<h2>Conclusion</h2>
<p>Because of the above
extraction of logic to a HOC,
we can now use the same HOC
in all our components
which render a loading indicator
while the data is being fetched.</p>
<p>The logic
to show a loading indicator
now resides in a HOC.
This makes the code easier
to maintain and less repetitive.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Opening non HTTPS sites in WebView in React Native]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/open-non-https-sites-in-webview-in-react-native"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/open-non-https-sites-in-webview-in-react-native.png"/>
      <id>https://www.bigbinary.com/blog/open-non-https-sites-in-webview-in-react-native</id>
      <published>2016-07-27T00:00:00.000Z</published>
      <updated>2016-07-27T00:00:00.000Z</updated>
      <author>
        <name>Chirag Shah</name>
        <uri>https://www.bigbinary.com/blog/authors/chiraggshah</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/open-non-https-sites-in-webview-in-react-native.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Using WebView in a React Native application allows us to reuse already built web pages. With iOS 9 or higher if our application attempts to connect to any HTTP server that doesn't support the latest...]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/open-non-https-sites-in-webview-in-react-native"><![CDATA[<p>Using WebView in a React Native application allows us to reuse already built web
pages.</p>
<p>With iOS 9 or higher if our application attempts to connect to any HTTP server
that doesn't support the latest SSL technology
<a href="http://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_1.2">(TLSv1.2)</a>,
WebView will fail and will not be able load the web pages.</p>
<p>Let's see this in action. Here we are trying to access a HTTP site via WebView
in React Native.</p>
<pre><code class="language-javascript">&lt;WebView style={styles.container} source={{ uri: &quot;http://del.icio.us&quot; }} /&gt;
</code></pre>
<p>Running that on an iPhone simulator with iOS version 9.0 or greater would show
following error.</p>
<pre><code class="language-plaintext">Error Loading Page
Domain: NSURLErrorDomain
Error Code: -1022
Description: The resource could not be loaded because
the App Transport Security policy requires the use of a
secure connection
</code></pre>
<p>Ideally, the site we are trying to connect to should have HTTPS enabled. However
there might be cases where we need to connect to sites where HTTPS is not
enabled.</p>
<p>For example, while developing the app, we might want to connect to local server
which is running just HTTP.</p>
<h2>Fix - Using Xcode</h2>
<p>To access HTTP sites inside our WebView, we need to open the project in Xcode
and open the <code>Info.plist</code> file.</p>
<p>In the list of keys, we will find <code>App Transport Security Settings</code>.</p>
<p>When we expand the section, we would find <code>localhost</code> inside the
<code>Exception Domains</code> and the key <code>NSTemporaryExceptionAllowsInsecureHTTPLoads</code>
with value <code>true</code>.</p>
<p>Because of this setting when we are connecting to localhost then app runs even
if server is running on HTTP and not on HTTPS.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2016/open-non-https-sites-in-webview-in-react-native/info-plist-before.png" alt="info plist before"></p>
<p>So in order to make our non HTTPS site run, we need to add our website url to
this whitelisting.</p>
<p>When we hover over the <code>Exception Domains</code> key, we would see a <code>+</code> sign at the
right hand side.</p>
<p>Click on it and add our domain here. Set the type to <code>dictionary</code>.</p>
<p>Now click on the domain we just entered and add
<code>NSTemporaryExceptionAllowsInsecureHTTPLoads</code> with type <code>Boolean</code> and value
<code>YES</code> similar to the one present for <code>localhost</code></p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2016/open-non-https-sites-in-webview-in-react-native/info-plist-after.png" alt="info plist after"></p>
<p>Re-run the app using <code>react-native run-ios</code> from the terminal and now the site
would be loaded.</p>
<p>If it doesn't work, then prior to running the app, do a clean build from xcode.</p>
<h2>Fix using any IDE</h2>
<p>By making the changes from XCode, if we look at the changes in info.plist file,
we would find a few lines of code added.</p>
<p>So if we don't want to open Xcode for the fix, we can add the following lines
directly in our info.plist.</p>
<p>Edit the node for the key <code>NSAppTransportSecurity</code> so that the whole node now
looks like this:</p>
<pre><code class="language-plist">&lt;key&gt;NSAppTransportSecurity&lt;/key&gt;
&lt;dict&gt;
    &lt;key&gt;NSExceptionDomains&lt;/key&gt;
    &lt;dict&gt;
        &lt;key&gt;del.icio.us&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;NSTemporaryExceptionAllowsInsecureHTTPLoads&lt;/key&gt;
            &lt;true/&gt;
        &lt;/dict&gt;
        &lt;key&gt;localhost&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;NSTemporaryExceptionAllowsInsecureHTTPLoads&lt;/key&gt;
            &lt;true/&gt;
        &lt;/dict&gt;
    &lt;/dict&gt;
&lt;/dict&gt;
</code></pre>
<p>Be sure to re-run the app using <code>react-native run-ios</code>. Now let's see how to
allow all the HTTP sites instead of whitelisting each and everyone</p>
<h4>Using Xcode</h4>
<p>Using Xcode : To allow all the non HTTPS sites, just delete the
<code>Exception Domains</code> from Xcode inside info.plist and add a new key
<code>Allow Arbitrary Loads</code> with the value <code>true</code>.</p>
<h4>Using any IDE</h4>
<p>Our <code>NSAppTransportSecurity</code> should just contain the following.</p>
<pre><code class="language-plist">&lt;key&gt;NSAppTransportSecurity&lt;/key&gt;
&lt;dict&gt;
    &lt;key&gt;NSAllowsArbitraryLoads&lt;/key&gt;
    &lt;true/&gt;
&lt;/dict&gt;
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[HTTP request headers on each WebView request]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/passing-request-headers-on-each-webview-request-in-react-native"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/passing-request-headers-on-each-webview-request-in-react-native.png"/>
      <id>https://www.bigbinary.com/blog/passing-request-headers-on-each-webview-request-in-react-native</id>
      <published>2016-07-26T00:00:00.000Z</published>
      <updated>2016-07-26T00:00:00.000Z</updated>
      <author>
        <name>Chirag Shah</name>
        <uri>https://www.bigbinary.com/blog/authors/chiraggshah</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/passing-request-headers-on-each-webview-request-in-react-native.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Send HTTP request headers on each WebView request in React Native]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/passing-request-headers-on-each-webview-request-in-react-native"><![CDATA[<p>Using
<a href="https://facebook.github.io/react-native/docs/webview.html">WebView</a>
in a React Native application allows
us to reuse already built web pages.</p>
<p>HTTP Headers are name/value pairs that
appear in both request and
response messages.
The purpose of headers is to supply
the web server with additional information
and control how content is returned.</p>
<p>In React Native, while opening
web pages via WebView Component,
we can pass headers to the HTTP request.
Refer to our
<a href="https://www.bigbinary.com/blog/passing-user-agent-or-custom-header-in-react-native-webview">previous blog</a>
for more on this.</p>
<pre><code class="language-javascript">&lt;WebView
  source={{
    uri: &quot;http://localhost:3000&quot;,
    headers: { &quot;custom-app-header&quot;: &quot;react-native-ios-app&quot; },
  }}
/&gt;
</code></pre>
<p>But there is a bug.
On subsequent requests from
inside the WebView,
the headers are not passed in the request.</p>
<p>First, let's try to understand
by recreating the bug.
We have created a simple node server
which will act as the backend
for the application and log the request
along with the custom header.</p>
<p>Here is our <code>server.js</code></p>
<pre><code class="language-javascript">var http = require(&quot;http&quot;);
var port = 9000;

function logRequest(request) {
  console.log(&quot;Processing request for: &quot;, request.url);
  console.log(&quot;Custom Header: &quot;, request.headers[&quot;custom-app-header&quot;]);
  console.log(&quot;Request Processed\n&quot;);
}

http
  .createServer(function (request, response) {
    response.writeHead(200, { &quot;Content-Type&quot;: &quot;text/html&quot; });
    switch (request.url) {
      case &quot;/&quot;:
        response.write(
          &quot;&lt;html&gt;&lt;body&gt;Welcome&lt;a href='/bye'&gt;Bye&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;&quot;
        );
        logRequest(request);
        break;
      case &quot;/bye&quot;:
        response.write(&quot;&lt;html&gt;&lt;body&gt;Bye&lt;a href='/'&gt;Welcome&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;&quot;);
        logRequest(request);
        break;
      default:
        break;
    }
    response.end();
  })
  .listen(port);
</code></pre>
<p>As we can see, the <code>welcome</code> page
has a link to <code>bye</code> and vice versa.
Let's start the node server by running
<code>node server.js</code>.</p>
<p>When we run the app on the simulator,
the <code>welcome</code> page opens up,
and in the server log,
we can verify that the request
header is being passed.</p>
<pre><code class="language-plaintext">Processing request for:  /
Custom Header:  react-native-ios-app
Request Processed
</code></pre>
<p>But when we click on the <code>Bye</code>
link from the <code>Welcome</code> page,
the server doesn't receive the
request header,
which can be verified from the log.</p>
<pre><code class="language-plaintext">Processing request for:  /bye
Custom Header:  undefined
Request Processed
</code></pre>
<p>And it can be verified again
that for any subsequent clicks
the request header does
not get passed. We can click on
<code>Welcome</code> and check the log again.</p>
<pre><code class="language-plaintext">Processing request for:  /
Custom Header:  undefined
Request Processed
</code></pre>
<p>We recently encountered this
bug and created an issue
<a href="https://github.com/facebook/react-native/issues/8693">here</a>.
Until the issue is fixed,
we have found a workaround.</p>
<h2>Workaround</h2>
<p>WebView provides a prop <code>onLoadStart</code>
which accepts a function that is
invoked when the WebView
starts loading.</p>
<p>We can use this prop to know
when a link is clicked
and then re-render the WebView
component with the new url.
Re-rendering the WebView component
will load the page as if it's the
first page and then the request
headers would be passed.</p>
<p>We know that in React,
a component re-renders itself when
any of its state changes.
The only thing which changes
here is the url, so let's move the
url to a state and
initialize it to the <code>Welcome</code> page
which is the root of the application.
And then use the <code>onLoadStart</code> prop
to change the url state to the clicked url.</p>
<p>Here's the new code.</p>
<pre><code class="language-javascript">class testApp extends Component {
  state = {
    url: &quot;http://localhost:3000&quot;,
  };

  render() {
    return (
      &lt;WebView
        onLoadStart={(navState) =&gt;
          this.setState({ url: navState.nativeEvent.url })
        }
        source={{
          uri: this.state.url,
          headers: { &quot;custom-app-header&quot;: &quot;react-native-ios-app&quot; },
        }}
      /&gt;
    );
  }
}
</code></pre>
<p>Now when we run the app,
we can verify in the backend that
the request headers are being sent
even when we click on <code>Bye</code> link.</p>
<pre><code class="language-plaintext">Processing request for:  /bye
Custom Header:  undefined
Request Processed

Processing request for:  /bye
Custom Header:  react-native-ios-app
Request Processed
</code></pre>
<p>One thing to note here is that,
when we click on the <code>Bye</code> link,
the request is not intercepted
from reaching the server.
We are just resending the
request by means of a component
re-render with the new url.</p>
<p>Hence in the log, we see two requests.
First request took place when
user clicked on the link,
and the second request occurred
when the component got re-rendered
with the required request headers.</p>
<p>This workaround might help us
to pass the request headers which
we intend to send to the backend
server until the issue gets fixed.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Platform specific styles in stylesheet, React Native]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/apply-platform-specific-styles-in-stylesheet-react-native"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/apply-platform-specific-styles-in-stylesheet-react-native.png"/>
      <id>https://www.bigbinary.com/blog/apply-platform-specific-styles-in-stylesheet-react-native</id>
      <published>2016-07-12T00:00:00.000Z</published>
      <updated>2016-07-12T00:00:00.000Z</updated>
      <author>
        <name>Bilal Budhani</name>
        <uri>https://www.bigbinary.com/blog/authors/bilalbudhani</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/apply-platform-specific-styles-in-stylesheet-react-native.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Apply platform specific styles in stylesheet in React Native]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/apply-platform-specific-styles-in-stylesheet-react-native"><![CDATA[<p>While writing cross platform applications
we need to add platform specific styles.
There are many ways of accomplishing this.</p>
<p>React Native
<a href="https://github.com/facebook/react-native/pull/7033">introduced</a>
<code>Platform.select</code> helper in
<a href="https://github.com/facebook/react-native/releases/tag/v0.28.0">version 0.28</a>
which allows us to write platform specific styles in a concise way.
In this blog we will see how to use this newly introduced feature.</p>
<h3>StyleSheet</h3>
<p>A basic stylesheet file might look something like this.</p>
<pre><code class="language-javascript">import { StyleSheet } from &quot;react-native&quot;;

export default StyleSheet.create({
  container: {
    flex: 1,
  },

  containerIOS: {
    padding: 4,
    margin: 2,
  },

  containerAndroid: {
    padding: 6,
  },
});
</code></pre>
<p>Now let's see how we can re-write this StyleSheet using <code>Platform.select</code>.</p>
<pre><code class="language-javascript">import { StyleSheet, Platform } from &quot;react-native&quot;;

export default StyleSheet.create({
  container: {
    flex: 1,
    ...Platform.select({
      ios: {
        padding: 4,
        margin: 2,
      },
      android: {
        padding: 6,
      },
    }),
  },
});
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[User agent or custom header in React Native WebView]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/passing-user-agent-or-custom-header-in-react-native-webview"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/passing-user-agent-or-custom-header-in-react-native-webview.png"/>
      <id>https://www.bigbinary.com/blog/passing-user-agent-or-custom-header-in-react-native-webview</id>
      <published>2016-07-10T00:00:00.000Z</published>
      <updated>2016-07-10T00:00:00.000Z</updated>
      <author>
        <name>Neeraj Singh</name>
        <uri>https://www.bigbinary.com/blog/authors/neerajsingh0101</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/passing-user-agent-or-custom-header-in-react-native-webview.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Change header or footer in React Native webview app using custom user agent]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/passing-user-agent-or-custom-header-in-react-native-webview"><![CDATA[<p>Using <a href="https://facebook.github.io/react-native/docs/webview.html">WebView</a> in a
React Native application allows us to reuse already built web pages.</p>
<p>We have seen that in most of the &quot;web view&quot; based applications the links in
header are mostly turned in native navigational components. It means server
should not be sending header if React Native component is asking for web pages.
However those headers should be present if the request is not coming from the
React Native app.</p>
<h2>Passing custom request headers</h2>
<p>We can configure React Native app to pass custom request headers when request is
made to the server to fetch pages.</p>
<pre><code class="language-javascript">let customHeaders = {
  &quot;X-DemoApp-Version&quot;: &quot;1.1&quot;,
  &quot;X-DemoApp-Type&quot;: &quot;demo-app-react-native&quot;,
};
</code></pre>
<p>While invoking WebView component we can pass <code>customHeaders</code> as shown below.</p>
<pre><code class="language-javascript">renderWebView() {
  return (
    &lt;WebView
      source={ {uri: this.props.url, headers: customHeaders} }
    /&gt;
  )
}
</code></pre>
<h2>Passing user agent</h2>
<p>React Native also allows us to pass &quot;userAgent&quot; as a prop. However it is only
supported by android version of React Native.</p>
<pre><code class="language-javascript">renderWebView() {
  return (
    &lt;WebView
      source={ {uri: this.props.url} }
      userAgent=&quot;demo-react-native-app&quot;
    /&gt;
  )
}
</code></pre>
<p>For iOS, we would need to add the following lines to our AppDelegate.m to set
the userAgent.</p>
<pre><code class="language-objectivec">NSString *newAgent = @&quot;demo-react-native-app&quot;;
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:newAgent, @&quot;UserAgent&quot;, nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
</code></pre>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Data exchange between React Native app and WebView]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/send-receive-data-between-react-native-and-webview"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/send-receive-data-between-react-native-and-webview.png"/>
      <id>https://www.bigbinary.com/blog/send-receive-data-between-react-native-and-webview</id>
      <published>2016-05-25T00:00:00.000Z</published>
      <updated>2016-05-25T00:00:00.000Z</updated>
      <author>
        <name>Bilal Budhani</name>
        <uri>https://www.bigbinary.com/blog/authors/bilalbudhani</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/send-receive-data-between-react-native-and-webview.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Send/Receive data between React Native app and WebView]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/send-receive-data-between-react-native-and-webview"><![CDATA[<p>A project we recently worked on needed some complicated charts.
We built
those charts using JavaScript library and it worked fine on browsers.</p>
<p>Now we need to build mobile app using
<a href="https://facebook.github.io/react-native/">React Native</a>
and it would take a
lot of time to build those charts natively. So we decided to use
WebView (Link is not available )
to render the html pages which already displays charts nicely.</p>
<p>React Native comes with <code>WebView</code>
component by default.
So rendering the html page using <code>WebView</code> was easy.
However, once the page is rendered the React Native app could not exchange
any data with the web page.</p>
<p>In this blog post we'll discuss how to
make React Native app communicate with the pages rendered using
<code>WebView</code>
with the help of
<a href="https://github.com/alinz/react-native-webview-bridge">react-native-webview-bridge</a>
library.</p>
<h2>What is React Native WebView Bridge ?</h2>
<p><code>react-native-webview-bridge</code>
is
a wrapper on top of React Native's <code>WebView</code> component with some extra features.</p>
<p>First we need to install
<a href="https://github.com/alinz/react-native-webview-bridge">react-native-webview-bridge</a>
package.</p>
<pre><code class="language-javascript">npm install react-native-webview-bridge --save
</code></pre>
<p>Next we need to import the <code>WebView</code> bridge module.</p>
<pre><code class="language-javascript">// ES6
import WebViewBridge from &quot;react-native-webview-bridge&quot;;

// ES5
let WebViewBridge = require(&quot;react-native-webview-bridge&quot;);
</code></pre>
<p>Now let's create a basic React component.
This component will be responsible for rendering html page using
<code>WebView</code>.</p>
<pre><code class="language-javascript">React.createClass({
  render: function () {
    return (
      &lt;WebViewBridge
        ref=&quot;webviewbridge&quot;
        onBridgeMessage={this.onBridgeMessage.bind(this)}
        source={{ uri: &quot;https://www.example.com/charts&quot; }}
      /&gt;
    );
  },
});
</code></pre>
<p>After the component is mounted then we will send data to web view.</p>
<pre><code class="language-javascript">componentDidMount() {
  let chartData = {data: '...'};

  // Send this chart data over to web view after 5 seconds.
  setTimeout(() =&gt; {
    this.refs.webviewbridge.sendToBridge(JSON.stringify(data));
  }, 5000);
},
</code></pre>
<p>Next, We will add code to receive data from web view.</p>
<pre><code class="language-javascript">onBridgeMessage: function (webViewData) {
  let jsonData = JSON.parse(webViewData);

  if (jsonData.success) {
    Alert.alert(jsonData.message);
  }
  console.log('data received', webViewData, jsonData);
  //.. do some react native stuff when data is received
}
</code></pre>
<p>At this time code should look something like this.</p>
<pre><code class="language-javascript">React.createClass({
  componentDidMount() {
    let chartData = { data: &quot;...&quot; };

    // Send this chart data over to web view after 5 seconds.
    setTimeout(() =&gt; {
      this.refs.webviewbridge.sendToBridge(JSON.stringify(data));
    }, 5000);
  },

  render: function () {
    return (
      &lt;WebViewBridge
        ref=&quot;webviewbridge&quot;
        onBridgeMessage={this.onBridgeMessage.bind(this)}
        source={{
          uri: &quot;https://www.example.com/charts&quot;,
        }}
      /&gt;
    );
  },

  onBridgeMessage: function (webViewData) {
    let jsonData = JSON.parse(webViewData);

    if (jsonData.success) {
      Alert.alert(jsonData.message);
    }
    console.log(&quot;data received&quot;, webViewData, jsonData);
    //.. do some react native stuff when data is received
  },
});
</code></pre>
<p>Okay, We've added all the React Native side of code.
We now need to add some JavaScript code on our web page to complete the functionality.</p>
<h2>Why do we need to add JavaScript snippet on my web page?</h2>
<p>This is a two way data exchange scenario. When our React Native app sends any data, this JavaScript snippet will parse that data and will trigger functions accordingly. We'll also be able to send some data back to React Native app from JavaScript.</p>
<p>The
<a href="https://github.com/alinz/react-native-webview-bridge#simple-example">example in the README</a>
of WebViewBridge library shows how to inject JavaScript snippet in React component.
However, we prefer JavaScript code to be added to web page directly
since it provides more control and flexibility.</p>
<p>Coming back to our implementation, Let's now add the snippet in our web page.</p>
<pre><code class="language-javascript">&lt;script&gt;
 (function () {
    if (WebViewBridge) {

      // This function gets triggered when data received from React Native app.
      WebViewBridge.onMessage = function (reactNativeData) {

        // Converts the payload in JSON format.
        var jsonData = JSON.parse(reactNativeData);

        // Passes data to charts for rendering
        renderChart(jsonData.data);

        // Data to send from web view to React Native app.
        var dataToSend = JSON.stringify({success: true, message: 'Data received'});

        // Keep calm and send the data.
        WebViewBridge.send(dataToSend);
      };
    }
  }())
&lt;/script&gt;
</code></pre>
<p>Done! We've achieved our goal of having a two way communication channel between our React Native app and the web page.</p>
<p>Checkout
<a href="https://github.com/alinz/react-native-webview-bridge/tree/master/examples/SampleRN20">this link</a>
for more examples of how to use WebView Bridge.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Using Image as a Container in React Native]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/using-image-as-a-container-in-react-native"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/using-image-as-a-container-in-react-native.png"/>
      <id>https://www.bigbinary.com/blog/using-image-as-a-container-in-react-native</id>
      <published>2016-04-28T00:00:00.000Z</published>
      <updated>2016-04-28T00:00:00.000Z</updated>
      <author>
        <name>Bilal Budhani</name>
        <uri>https://www.bigbinary.com/blog/authors/bilalbudhani</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/using-image-as-a-container-in-react-native.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Add background images as container in React Native apps]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/using-image-as-a-container-in-react-native"><![CDATA[<p>Adding a nice looking background to a screen makes an app visually appealing. It
also makes the app look more sleek and elegant. Let us see how we can leverage
this technique in React Native and add an image as a background.</p>
<p>We’ll need to create different sizes of the background image, which we’re going
to use as a container. React Native will pick up appropriate image based on the
device’s dimension (check
<a href="http://facebook.github.io/react-native/docs/images.html#content">Images guide</a>
for more information).</p>
<pre><code class="language-plaintext">- login-background.png (375x667)
- login-background@2x.png (750x1134)
- login-background@3x.png (1125x2001)
</code></pre>
<p>Now we’ll use these images in our code as container.</p>
<pre><code class="language-javascript">//...
render() {
    return (
      &lt;Image
        source={require('./images/login-background.png')}
        style={styles.container}&gt;
        &lt;Text style={styles.welcome}&gt;
          Welcome to React Native!
        &lt;/Text&gt;
        &lt;Text style={styles.instructions}&gt;
          To get started, edit index.ios.js
        &lt;/Text&gt;
        &lt;Text style={styles.instructions}&gt;
          Press Cmd+R to reload,{'\n'}
          Cmd+D or shake for dev menu
        &lt;/Text&gt;
      &lt;/Image&gt;
    );
  }
//...

const styles = StyleSheet.create({
  container: {
    flex: 1,
    width: undefined,
    height: undefined,
    backgroundColor:'transparent',
    justifyContent: 'center',
    alignItems: 'center',
  },
});
</code></pre>
<p>We’ve intentionally left height and width of the image as <code>undefined</code>. This will
let React Native take the size of the image from the image itself. This way, we
can use Image component as View and add other components as a children to build
UI.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2016/using-image-as-a-container-in-react-native/image-as-container-react-native.png" alt="image as container in react native"></p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[Using Stripe API in React Native with fetch]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/using-stripe-api-in-react-native-with-fetch"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/using-stripe-api-in-react-native-with-fetch.png"/>
      <id>https://www.bigbinary.com/blog/using-stripe-api-in-react-native-with-fetch</id>
      <published>2015-11-03T00:00:00.000Z</published>
      <updated>2015-11-03T00:00:00.000Z</updated>
      <author>
        <name>Chirag Shah</name>
        <uri>https://www.bigbinary.com/blog/authors/chiraggshah</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/using-stripe-api-in-react-native-with-fetch.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Use Stripe API in React Native using fetch]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/using-stripe-api-in-react-native-with-fetch"><![CDATA[<p><a href="https://stripe.com">Stripe</a> makes it easy to accept payments online. Stripe
offers an <a href="https://www.npmjs.com/package/stripe">npm package</a> with
<a href="https://stripe.com/docs/api/node">nice documentation</a>.</p>
<h2>Problem with using Stripe in React Native</h2>
<p>I added stripe to my React Native application using following command.</p>
<pre><code class="language-plaintext">npm install stripe --save
</code></pre>
<p>Added Stripe to the project as shown below.</p>
<pre><code class="language-plaintext">var stripe = require('stripe')('stripe API key');
</code></pre>
<p>And now I'm getting following error.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2015/using-stripe-api-in-react-native-with-fetch/http_error_in_react_native.png" alt="could not mount"></p>
<p>This's because npm package uses <a href="https://stripe.com/docs/stripe.js">stripe.js</a>
and stripe.js needs <a href="https://nodejs.org/api/http.html">http</a> provided by
Node.JS.</p>
<p>Our React Native code does not actually run on Node.JS. I know while building
React Native we use NPM and we have a node server running in the background so
it feels like we are in Node.JS land and we can use everything Node.JS has to
offer. But that's not true. React Native code can't depend on Node.JS because
Node.JS is not shipped with ios. It means we can't use any of Node.JS packages
including <code>http</code>. It means we can't use <code>stripe</code> npm module.</p>
<p>Now you can remove <code>require('stripe')</code> line that was added in the last step.</p>
<h2>Solution</h2>
<p>React Native comes with <a href="https://fetch.spec.whatwg.org">Fetch</a>
<a href="https://github.com/github/fetch">api</a>. From the documentation</p>
<blockquote>
<p>The Fetch API provides a JavaScript interface for accessing an manipulating
parts of the HTTP pipeline, such as requests and responses. It also provides a
global fetch() method that provides an easy, logical way to fetch resources
asynchronously across the network.</p>
</blockquote>
<p>stripe.js is a nice wrapper around stripe api. stripe api is very well
documented and is easy to use. Since we can't use stripe.js we will use stripe
api.</p>
<p>We will use fetch to
<a href="https://stripe.com/docs/api#create_card_token">create a credit card token using api</a>.</p>
<pre><code class="language-javascript">return fetch(&quot;https://api.stripe.com/v1/tokens&quot;, {
  method: &quot;post&quot;,
  headers: {
    Accept: &quot;application/json&quot;,
    &quot;Content-Type&quot;: &quot;application/x-www-form-urlencoded&quot;,
    Authorization: &quot;Bearer &quot; + &quot;&lt;YOUR-STRIPE-API-KEY&gt;&quot;,
  },
  body: formBody,
});
</code></pre>
<p>Here, the header has 3 keys. Lets go through them one-by-one:</p>
<ul>
<li><code>'Accept': 'application/json'</code> : Designates the content to be in JSON format.</li>
<li><code>'Content-Type': 'application/x-www-form-urlencoded'</code> : This tells the
endpoint that the payload will be one giant query string where name and value
pairs will be separated by the ampersand.</li>
<li><code>'Authorization': 'Bearer ' + '&lt;YOUR-STRIPE-API-KEY&gt;'</code> : This key is to
authorize our actions on Stripe. Here <code>Bearer</code> is just a prefix which we need
to attach to the api-key because Stripe uses OAuth 2.0 . You can read more on
the Bearer token usage
<a href="http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html">here</a> .</li>
</ul>
<p>Payload needs to contain credit card details.</p>
<pre><code class="language-javascript">var cardDetails = {
  &quot;card[number]&quot;: &quot;1111 2222 3333 4444&quot;,
  &quot;card[exp_month]&quot;: &quot;01&quot;,
  &quot;card[exp_year]&quot;: &quot;2020&quot;,
  &quot;card[cvc]&quot;: &quot;123&quot;,
};
</code></pre>
<p>Since the <code>Content-Type</code> is <code>application/x-www-form-urlencoded</code>, the payload
should be one query string. An example of this would be:
<code>city=Miami&amp;state=Florida</code></p>
<p>Let's prepare a proper payload.</p>
<pre><code class="language-plaintext">var formBody = [];
for (var property in cardDetails) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(cardDetails[property]);
  formBody.push(encodedKey + &quot;=&quot; + encodedValue);
}
formBody = formBody.join(&quot;&amp;&quot;);
</code></pre>
<p>That's it. Now we can attach <code>formBody</code> to the body part of the fetch request
and we are good to go.</p>
<h2>Final solution</h2>
<p>Here's the whole code snippet.</p>
<pre><code class="language-javascript">&quot;use strict&quot;;

var stripe_url = &quot;https://api.stripe.com/v1/&quot;;
var secret_key = &quot;&lt;YOUR-STRIPE-API-KEY&gt;&quot;;

module.exports.createCardToken = function (cardNumber, expMonth, expYear, cvc) {
  var cardDetails = {
    &quot;card[number]&quot;: cardNumber,
    &quot;card[exp_month]&quot;: expMonth,
    &quot;card[exp_year]&quot;: expYear,
    &quot;card[cvc]&quot;: cvc,
  };

  var formBody = [];
  for (var property in cardDetails) {
    var encodedKey = encodeURIComponent(property);
    var encodedValue = encodeURIComponent(cardDetails[property]);
    formBody.push(encodedKey + &quot;=&quot; + encodedValue);
  }
  formBody = formBody.join(&quot;&amp;&quot;);

  return fetch(stripe_url + &quot;tokens&quot;, {
    method: &quot;post&quot;,
    headers: {
      Accept: &quot;application/json&quot;,
      &quot;Content-Type&quot;: &quot;application/x-www-form-urlencoded&quot;,
      Authorization: &quot;Bearer &quot; + secret_key,
    },
    body: formBody,
  });
};
</code></pre>
<p>This is an example of registering a credit card with stripe and getting the
token. Similar implementations can be done for other API endpoints.</p>
]]></content>
    </entry>
  <entry>
      <title type="text"><![CDATA[How to test React Native App on a real iPhone]]></title>
      <link rel="alternate" type="text/html" href="https://www.bigbinary.com/blog/how-to-test-react-native-app-on-real-iphone"/>
      <link rel="enclosure" type="image/png" href="https://www.bigbinary.com/blog/images/social_preview_images/generated/how-to-test-react-native-app-on-real-iphone.png"/>
      <id>https://www.bigbinary.com/blog/how-to-test-react-native-app-on-real-iphone</id>
      <published>2015-08-25T00:00:00.000Z</published>
      <updated>2015-08-25T00:00:00.000Z</updated>
      <author>
        <name>Chirag Shah</name>
        <uri>https://www.bigbinary.com/blog/authors/chiraggshah</uri>
      </author>
      <category term="React Native"/>
      <media:thumbnail url="https://www.bigbinary.com/blog/images/social_preview_images/generated/how-to-test-react-native-app-on-real-iphone.png" width="1200" height="630"/>
      <summary type="text"><![CDATA[Simulators are great but one needs to test on real mobile devices to get a real feel for how the app will behave on real phones. In this blog we are going to show how to test React Native app on a real iPhone.]]></summary>
      <content type="html" xml:base="https://www.bigbinary.com/blog/how-to-test-react-native-app-on-real-iphone"><![CDATA[<p>I have been developing a new iOS app using
<a href="https://facebook.github.io/react-native/">React Native</a>. I have been testing it
using simulator provided by Xcode. Now it's time to test the app using a real
device. One could ask why test on a real device if it works perfectly on a
simulator. Here are some of the reasons.</p>
<ul>
<li>There are a number of device specific features which are not testable on a
simulator. Phone calls, camera, gps data, compass and vibration are a few of
them.</li>
<li>Testing unexpected cases that can only be tested on a real device. Like how
your application handles incoming calls, low memory situations, low disk
space, limited data connectivity etc.</li>
<li>Hardware-wise, your device is different than your Mac. If your app is graphics
intensive and requires a lot of CPU usage, it might work seamlessly on your
simulator depending on your Mac's specifications. But it might be laggy and
glitchy on the real device.</li>
</ul>
<p>Now let's look into how you can start testing your React Native app on an real
iPhone.</p>
<h2>Step 1 - Plug in your device</h2>
<p>Plug in your device to your Mac and open Xcode. You will be able to select your
device to the right of the Play and Stop buttons.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2015/how-to-test-react-native-app-on-real-iphone/select-device.png" alt="select device"></p>
<p>You might run into one of the following two errors if you have not enrolled into
Apple's Developer Program.</p>
<h2>Error 1 : Failed to code sign</h2>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2015/how-to-test-react-native-app-on-real-iphone/xcode-error1.png" alt="xcode error 1"></p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2015/how-to-test-react-native-app-on-real-iphone/xcode-error2.png" alt="xcode error 2"></p>
<p>To fix above issues please enroll in Apple Developer program.</p>
<h2>Error 2 : Disk Image could not be mounted</h2>
<pre><code class="language-plaintext">The Developer Disk Image could not be mounted :
You may be running a version of iOS that is not supported by this version of XCode
</code></pre>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2015/how-to-test-react-native-app-on-real-iphone/could-not-mount.png" alt="could not mount"></p>
<p>This can happen if your iOS version is not supported by your current version of
Xcode. To fix this, just update your Xcode to the latest version from the App
Store.</p>
<h2>Step 2 - Set right deployment target</h2>
<p>In your Xcode project setup the <code>Deployment Target</code> should be set to less than
or equal to the iOS version installed on the device.</p>
<p>If your iPhone is running iOS 7.0 and you have set &quot;Deployment Target&quot; as 8.0
then the app <strong>will not</strong> work. If your iPhone is running iOS 8.0 and you have
set &quot;Deployment Target&quot; as 7.0 then the app <strong>will</strong> work.</p>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2015/how-to-test-react-native-app-on-real-iphone/deployment-target.png" alt="deployment target"></p>
<h2>Step 3 - Fix &quot;Could not connect to development server&quot; error</h2>
<p>So the app is installed and you can see the launch screen. That's great. But
soon you might get following error on your iPhone.</p>
<pre><code class="language-plaintext">Could not connect to development server.
Ensure node server is running and available on the same
network – run ‘npm start’ from react-native root.
</code></pre>
<p><img src="https://www.bigbinary.com/blog/images/images_used_in_blog/2015/how-to-test-react-native-app-on-real-iphone/connection-error.PNG" alt="connection error"></p>
<p>To fix this open <code>AppDelegate.m</code> file in your project's iOS folder.</p>
<p>Locate line mentioned below and replace <code>localhost</code> with your Mac IP address
e.g. <code>192.168.x.x</code>.</p>
<p>To find the ip address of your Mac this is what ReactNative suggests us to do.</p>
<blockquote>
<p>you can get ip by typing <code>ifconfig</code> into the terminal and selecting the * &gt;
<code>inet</code> value under <code>en0:</code>.</p>
</blockquote>
<pre><code class="language-objectivec">jsCodeLocation = [NSURL URLWithString:@&quot;http://localhost:8081/index.ios.bundle&quot;];
</code></pre>
<p>Save and click run again. This will fix the error.</p>
<h2>Step 3 - Fix connecting to API hosted on local development server</h2>
<p>Now the app is installed and you can navigate through the app screens. If the
app attempts to make API call to the server running locally on the machine then
depending on how the local server was started it could be a problem.</p>
<p>In my case, I have a Ruby on Rails application running on my local machine. I
had started my rails server by executing command <code>rails server</code>.</p>
<p>To do this, the app should be able to access the rails server using the private
ip of the server e.g. <code>192.168.x.x:3000</code>. Turned out that I had started my rails
server using command <code>rails server</code>.</p>
<p>Because of
<a href="http://guides.rubyonrails.org/4_2_release_notes.html#default-host-for-rails-server">change in Rails 4.2</a>
rails server listens to <code>localhost</code> and not <code>0.0.0.0</code>.</p>
<p>The rails guide further says following.</p>
<blockquote>
<p>with this change you will no longer be able to access the Rails server from a
different machine, for example if your development environment is in a virtual
machine and you would like to access it from the host machine. In such cases,
please start the server with rails server -b 0.0.0.0 to restore the old
behavior.</p>
</blockquote>
<p>In this case iPhone is trying to talk to Rails server so Rails server must be
started using following command.</p>
<pre><code class="language-plaintext">rails server -b 0.0.0.0
or
rails server --binding=0.0.0.0
</code></pre>
<p>By doing so, now you can connect to your Rails app from your local network, by
browsing to <code>http://192.168.x.x:3000</code>.</p>
<h2>Summary</h2>
<p>These were some of the issues I came across while testing my iOS app on an
actual device and how I fixed them. Hopefully, this blog post helps you fix
these error cases get you started on testing quickly.</p>
]]></content>
    </entry>
</feed>