<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josie Daw</title>
    <description>The latest articles on DEV Community by Josie Daw (@josie).</description>
    <link>https://dev.to/josie</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F682127%2F8a55c421-aaac-4561-98ea-faa3beb6d938.jpg</url>
      <title>DEV Community: Josie Daw</title>
      <link>https://dev.to/josie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josie"/>
    <language>en</language>
    <item>
      <title>How to Add Background Audio to Expo Apps</title>
      <dc:creator>Josie Daw</dc:creator>
      <pubDate>Mon, 22 Jan 2024 03:19:16 +0000</pubDate>
      <link>https://dev.to/josie/how-to-add-background-audio-to-expo-apps-3fgc</link>
      <guid>https://dev.to/josie/how-to-add-background-audio-to-expo-apps-3fgc</guid>
      <description>&lt;p&gt;One of the most common problems that I've come across with audio with Expo apps is trying to get the audio to play even while the app is no longer on screen/in focus. There are many use cases where you want audio to persist from your app even while using another app or when the screen is locked.&lt;/p&gt;

&lt;p&gt;The guide below is a simple tutorial for how to use Expo AV to play audio in the background of your Expo app.&lt;/p&gt;




&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Get Started&lt;/li&gt;
&lt;li&gt;Install Expo AV&lt;/li&gt;
&lt;li&gt;Set Up a Basic Audio Button&lt;/li&gt;
&lt;li&gt;Add Allow Background Playing&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Get Started
&lt;/h3&gt;

&lt;p&gt;First, create an Expo app. You can follow &lt;a href="https://docs.expo.dev/tutorial/create-your-first-app/" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt; if it is your first time using Expo.&lt;/p&gt;

&lt;p&gt;Once you have your basic app set up, you can run it on Expo Go (or an emulator/device if you prefer).&lt;/p&gt;




&lt;h3&gt;
  
  
  Install Expo AV
&lt;/h3&gt;

&lt;p&gt;Expo has a great audio library ready for you to use, you just need to install it. Run &lt;code&gt;npx expo install expo-av&lt;/code&gt;. &lt;/p&gt;




&lt;h3&gt;
  
  
  Set Up a Basic Audio Button
&lt;/h3&gt;

&lt;p&gt;For this tutorial, we will create a very basic audio player based on a simple play button (in Typescript)&lt;/p&gt;

&lt;p&gt;First, create a new file called &lt;code&gt;AudioButton.tsx&lt;/code&gt;. In this case, we will pass a URL from the parent component, so we will add it as a props with &lt;code&gt;AudioButtonProps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then create two basic states to hold our playing status and sound status.&lt;/p&gt;

&lt;p&gt;Next, we want to create a &lt;code&gt;useEffect&lt;/code&gt; to prepare the audio on load. Inside the &lt;code&gt;useEffect&lt;/code&gt;, we will set all of the important options to enable audio to play in the background in an Expo app. &lt;/p&gt;

&lt;p&gt;You will notice that we have &lt;code&gt;staysActiveInBackground&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;. This is a basic requirement, but is not enough on its own for the background audio to work. &lt;/p&gt;

&lt;p&gt;The most common problem that people have with Expo AV is that they don't set all of the options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;staysActiveInBackground: true,
playsInSilentModeIOS: true,
interruptionModeIOS: InterruptionModeIOS.DuckOthers,
interruptionModeAndroid: InterruptionModeAndroid.DuckOthers,
shouldDuckAndroid: true,
playThroughEarpieceAndroid: true,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these options needs to be set for audio to play in the background in every case on different devices. &lt;/p&gt;

&lt;p&gt;For &lt;code&gt;interruptionModeIOS&lt;/code&gt; and &lt;code&gt;interruptionModeAndroid&lt;/code&gt;, you can choose &lt;code&gt;MixWithOthers&lt;/code&gt;, &lt;code&gt;DoNotMix&lt;/code&gt;, or &lt;code&gt;DuckOthers&lt;/code&gt;. We have set &lt;code&gt;DuckOthers&lt;/code&gt; so that any other audio nicely fades out, which makes for a more pleasant user experience.&lt;/p&gt;

&lt;p&gt;You can read more details about these options on the &lt;a href="https://docs.expo.dev/versions/latest/sdk/audio" rel="noopener noreferrer"&gt;Expo Audio&lt;/a&gt; page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AudioButton.tsx

import { Audio, InterruptionModeAndroid, InterruptionModeIOS } from 'expo-av';
import { Sound } from 'expo-av/build/Audio';

interface AudioButtonProps {
  audioUrl: string;
}

const AudioButton = ({ audioUrl }: AudioButtonProps) =&amp;gt; {
  const [isPlaying, setIsPlaying] = useState&amp;lt;boolean&amp;gt;(false);
  const [sound, setSound] = useState&amp;lt;Sound | null&amp;gt;(null);

  useEffect(() =&amp;gt; {
    Audio.setAudioModeAsync({
        staysActiveInBackground: true,
        playsInSilentModeIOS: true,
        interruptionModeIOS: InterruptionModeIOS.DuckOthers,
        interruptionModeAndroid: InterruptionModeAndroid.DuckOthers,
        shouldDuckAndroid: true,
        playThroughEarpieceAndroid: true,
    });
    return sound
      ? () =&amp;gt; {
        sound.unloadAsync();
      }
      : undefined;
  }, [sound]);


};

export default AudioButton;

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

&lt;/div&gt;



&lt;p&gt;Next, we will create a function to play the sound and a little button to trigger it with. Expo comes with Vector icons built-in, so you can change the &lt;code&gt;FontAwesome&lt;/code&gt; icon to any you prefer. You can search the icons &lt;a href="https://icons.expo.fyi/Index" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; const playAudio = async () =&amp;gt; {
      // Set and play the sound
      const { sound: newSound } = await Audio.Sound.createAsync({ uri: audioUrl });
      setSound(newSound);

      setIsPlaying(true);
      await newSound.playAsync();

      // After the sound has finished, update the state so that the icon changes
      newSound.setOnPlaybackStatusUpdate((status) =&amp;gt; {
        if ('didJustFinish' in status &amp;amp;&amp;amp; status.didJustFinish) {
          setIsPlaying(false);
        }
      });
  };

return (
    &amp;lt;TouchableOpacity onPress={playAudio}&amp;gt;
      &amp;lt;FontAwesome name={isPlaying ? 'volume-up' : 'play'} size={15} color="#6b7280" /&amp;gt;
    &amp;lt;/TouchableOpacity&amp;gt;
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's also add a bit of styling so it looks like a nice round play button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;TouchableOpacity style={styles.button} onPress={playAudio}&amp;gt;
      &amp;lt;FontAwesome name={isPlaying ? 'volume-up' : 'play'} size={15} color="#6b7280" /&amp;gt;
&amp;lt;/TouchableOpacity&amp;gt;


// Include this after the AudioButton export
const styles = StyleSheet.create({
  button: {
    height: 30,
    width: 30,
    borderRadius: 15, // Half of the height/width
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'transparent',
    borderWidth: 1,
    borderColor: '#e5e7eb',
    marginHorizontal: 5,
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will put all of the code together so you can see where all of the pieces go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FontAwesome } from '@expo/vector-icons';
import { Audio, InterruptionModeAndroid, InterruptionModeIOS } from 'expo-av';
import { Sound } from 'expo-av/build/Audio';
import React, { useEffect, useState } from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';

interface AudioButtonProps {
  audioUrl: string;
}

const AudioButton = ({ audioUrl}: AudioButtonProps) =&amp;gt; {
  const [isPlaying, setIsPlaying] = useState&amp;lt;boolean&amp;gt;(false);
  const [sound, setSound] = useState&amp;lt;Sound | null&amp;gt;(null);

  // Prepare the audio
  useEffect(() =&amp;gt; {
    Audio.setAudioModeAsync({
        staysActiveInBackground: true,
        playsInSilentModeIOS: true,
        interruptionModeIOS: InterruptionModeIOS.DuckOthers,
        interruptionModeAndroid: InterruptionModeAndroid.DuckOthers,
        shouldDuckAndroid: true,
        playThroughEarpieceAndroid: true,
    });
    return sound
      ? () =&amp;gt; {
        sound.unloadAsync();
      }
      : undefined;
  }, [sound]);

  // Trigger the audio
  const playAudio = async () =&amp;gt; {
      const { sound: newSound } = await Audio.Sound.createAsync({ uri: audioUrl });
      setSound(newSound);

      setIsPlaying(true);
      await newSound.playAsync();

      newSound.setOnPlaybackStatusUpdate((status) =&amp;gt; {
        if ('didJustFinish' in status &amp;amp;&amp;amp; status.didJustFinish) {
          setIsPlaying(false);
        }
      });
    }
  };

  return (
    &amp;lt;TouchableOpacity style={styles.button} onPress={playAudio}&amp;gt;
      &amp;lt;FontAwesome name={isPlaying ? 'volume-up' : 'play'} size={15} color="#6b7280" /&amp;gt;
    &amp;lt;/TouchableOpacity&amp;gt;
  );
};

export default AudioButton;

const styles = StyleSheet.create({
  button: {
    height: 30,
    width: 30,
    borderRadius: 15, // Half of the height/width
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'transparent',
    borderWidth: 1,
    borderColor: '#e5e7eb',
    marginHorizontal: 5,
  },
});

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

&lt;/div&gt;



&lt;p&gt;Now we have our audio button with some background settings included. You can include this button anywhere in your app with &lt;code&gt;&amp;lt;AudioButton audioUrl="https://some-audio-url-here.com" /&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However, we still have to make some extra changes to ensure that it will work with iOS and Android devices.&lt;/p&gt;




&lt;h3&gt;
  
  
  Add Allow Background Playing
&lt;/h3&gt;

&lt;p&gt;For iOS and Android to allow background audio, you should update your &lt;code&gt;app.json&lt;/code&gt;/&lt;code&gt;app.config.js&lt;/code&gt; to include &lt;code&gt;UIBackgroundModes: ['audio']&lt;/code&gt; and &lt;code&gt;permissions: ['WAKE_LOCK']&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;permissions: ['WAKE_LOCK']&lt;/code&gt; will keep the Android version of the app active while the screen is locked, but can drain power, so be careful of using this permission if it is not required.&lt;/p&gt;

&lt;p&gt;If you do not include &lt;code&gt;UIBackgroundModes: ['audio']&lt;/code&gt; your app can be rejected by the App Store reviewers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "ios": {
    "buildNumber": "1",
    "infoPlist": {
      "UIBackgroundModes": ["audio"]
    },
    "bundleIdentifier": "com.fakeapp"
  },
  "android": {
    "versionCode": 1,
    "adaptiveIcon": {
      "foregroundImage": "./assets/adaptive-icon.png",
      "backgroundColor": "#FFF"
    },
    "package": "com.fakeapp",
    "permissions": ["WAKE_LOCK"],
    "googleServicesFile": "./google-services.json"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding all of these, you may be wondering during your own testing why it doesn't seem to work. If you are using the Expo Go app or Expo development build, the &lt;strong&gt;background audio mode will not work&lt;/strong&gt; correctly, because when you close your screen or move to another app, your app will lose connection to Expo metro and stop working. &lt;/p&gt;

&lt;p&gt;In order to confirm that the background audio definitely works, you will need to create a real build and try it on TestFlight/Internal Testing. (Just make sure to test your audio button while the app is open before creating a build for it!)&lt;/p&gt;




&lt;p&gt;Thanks for following along with this short tutorial for how to add background audio to Expo apps! If you're interested in learning more about me, you can visit my portfolio &lt;a href="https://josiedaw.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are facing an error anywhere along the way, feel free to leave a comment below and we can try to debug it together!&lt;/p&gt;

</description>
      <category>expo</category>
      <category>reactnative</category>
      <category>programming</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Adding Google AdMob to Expo Apps</title>
      <dc:creator>Josie Daw</dc:creator>
      <pubDate>Sun, 21 Jan 2024 10:48:37 +0000</pubDate>
      <link>https://dev.to/josie/adding-google-admob-to-expo-apps-2din</link>
      <guid>https://dev.to/josie/adding-google-admob-to-expo-apps-2din</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;p&gt;1. Getting Started&lt;br&gt;
2. Using Expo Development Builds&lt;br&gt;
3. Preparing AdMob&lt;br&gt;
4. Using React Native Google Mobile Ads &lt;br&gt;
5. Creating a Banner Ad&lt;br&gt;
6. Creating an Interstitial Ad&lt;br&gt;
7. Configure Ads for Production&lt;br&gt;
8. Common Problems with Google Admob for Expo/React Native&lt;/p&gt;


&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;This post is a brief guide on adding banner ads and interstitial ads to a simple Expo project using Google AdMob and React Native Google Mobile Ads. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create your &lt;a href="https://docs.expo.dev/tutorial/create-your-first-app/" rel="noopener noreferrer"&gt;Expo project&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a &lt;a href="https://apps.admob.com/v2/home" rel="noopener noreferrer"&gt;Google AdMob&lt;/a&gt; account and make sure to complete the verification process. &lt;/li&gt;
&lt;/ol&gt;


&lt;h3&gt;
  
  
  Using Expo Development Builds
&lt;/h3&gt;

&lt;p&gt;Since we will later install React Native Google Mobile Ads, we will not be able to use the Expo Go app to test. As a result, we will need to use the Expo development builds to test our app. &lt;/p&gt;

&lt;p&gt;You can follow &lt;a href="https://docs.expo.dev/develop/development-builds/create-a-build/" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt; from Expo to setup a development build.&lt;/p&gt;

&lt;p&gt;Add the following lines to your &lt;code&gt;package.json&lt;/code&gt; (after following the tutorial steps) so that you can easily build development models from your command line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
     ...
     "dev:build:ios": "eas build --profile development --platform ios",
     "dev:build:android": "eas build --profile development --platform android",
  },

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

&lt;/div&gt;






&lt;h3&gt;
  
  
  Preparing AdMob
&lt;/h3&gt;

&lt;p&gt;Since React Native is a cross-platform framework, you will need to create an app for both iOS and Android. You will need to have apps already published on the App and Play stores to register them with AdMob. If you are following this guide before registering your app on any stores, make sure to just use the test IDs. &lt;/p&gt;

&lt;p&gt;After creating the apps in Google AdMob, select the app and then select 'App Settings'. Get the App ID for both Android and iOS. The format of the App ID is always &lt;code&gt;ca-app-pub-12345678910~123456459&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvec8ju403f8nwghebdc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvec8ju403f8nwghebdc.png" alt="Google AdMob app view" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;app.json&lt;/code&gt;/&lt;code&gt;app.config.js&lt;/code&gt;, outside of "expo", add a new object with the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "expo": ...
  "react-native-google-mobile-ads": {
    "android_app_id": "ca-app-pub-12345678910~123456459",
    "ios_app_id": "ca-app-pub-12345678910~123456459",
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will also need to register your test devices if you are not using emulators. You can follow &lt;a href="https://support.google.com/admob/answer/9691433#add" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; to register your devices with AdMob.&lt;/p&gt;

&lt;h4&gt;
  
  
  Don't Forget to Follow Advertising Regulations
&lt;/h4&gt;

&lt;p&gt;Many countries around the world now have explicit consent requirements to display any ads at all. Luckily, Google AdMob and React Native Google Mobile Ads make this easy to do. From the Google AdMob dashboard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click Privacy &amp;amp; Messaging&lt;/li&gt;
&lt;li&gt;Create messaging for European Regulations, US State Regulations, and any other options. &lt;/li&gt;
&lt;li&gt;Click "Publish" for each message.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Using React Native Google Mobile Ads
&lt;/h3&gt;

&lt;p&gt;Start by installing React Native Google Mobile Ads with &lt;code&gt;npm install react-native-google-mobile-ads&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you need to use static frameworks, you should follow an additional step and add this to your plugins in &lt;code&gt;app.json&lt;/code&gt;/&lt;code&gt;app.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "plugins": [
      [
        "expo-build-properties",
        {
          "ios": {
            "useFrameworks": "static"
          }
        }
      ]
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to initialize the ads when the app first loads, so on your &lt;code&gt;App.js&lt;/code&gt; or your root &lt;code&gt;_layout.jsx&lt;/code&gt;/&lt;code&gt;_layout.tsx&lt;/code&gt;, add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import mobileAds from 'react-native-google-mobile-ads';

// Go inside your component/function

// Initialize Google Mobile Ads SDK
useEffect(() =&amp;gt; {
    (async () =&amp;gt; {
      // Google AdMob will show any messages here that you just set up on the AdMob Privacy &amp;amp; Messaging page
      const { status: trackingStatus } = await requestTrackingPermissionsAsync();
      if (trackingStatus !== 'granted') {
        // Do something here such as turn off Sentry tracking, store in context/redux to allow for personalized ads, etc.
      }

      // Initialize the ads
      await mobileAds().initialize();
    })();
}, [])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are now ready to create our first ad! &lt;/p&gt;




&lt;h3&gt;
  
  
  Creating a Banner Ad
&lt;/h3&gt;

&lt;p&gt;Banner ads are one of the easiest ways to insert ads into your app without severely interrupting the user experience. You can easily insert them at natural breakpoints in your Views/components.&lt;/p&gt;

&lt;p&gt;To insert a banner ad into your app, you must first create one on Google AdMob. For both iOS and Android, go to each App -&amp;gt; Ad Units -&amp;gt; Add Ad Unit -&amp;gt; Select Banner Ad.&lt;/p&gt;

&lt;p&gt;You can give the ad any name and adjust the advanced settings to your preferences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny4rev2dlkdfq1gu1noq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fny4rev2dlkdfq1gu1noq.png" alt="Google AdMob ad view" width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be using the Ad ID for the next stage. The Ad ID is &lt;em&gt;different&lt;/em&gt; from the App ID. The Ad ID always has a structure of &lt;code&gt;ca-app-pub-12345678910/12345678910&lt;/code&gt;. An easy way to tell the difference is that the App ID has a ~ and the Ad ID has a /. &lt;/p&gt;

&lt;p&gt;First, install Expo device to be able to display the correct banners: &lt;code&gt;npx expo install expo-device&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, let's create a special component to hold our banner ad so that we can easily reuse it anywhere in our app. &lt;/p&gt;

&lt;p&gt;Create a new file called &lt;code&gt;InlineAd.tsx&lt;/code&gt; (or &lt;code&gt;InlineAd.jsx&lt;/code&gt;) and use something like the below code.&lt;/p&gt;

&lt;p&gt;By using &lt;code&gt;isAdLoaded&lt;/code&gt; and the View style, we can minimize the amount of blank space showing on the app when an ad has not loaded.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Remember, you should put your Ad IDs in environmental variables. The fake IDs below are for display purposes only.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// InlineAd.tsx

import { View } from 'react-native';
import * as Device from 'expo-device';
import React, { useState } from 'react';
import { BannerAd, BannerAdSize, TestIds } from 'react-native-google-mobile-ads';

const iosAdmobBanner = "ca-app-pub-12345678910/12345678910";
const androidAdmobBanner = "ca-app-pub-12345678910/12345678910";
const productionID = Device.osName === 'Android' ? androidAdmobBanner : iosAdmobBanner;

const InlineAd = () =&amp;gt; {
  const [isAdLoaded, setIsAdLoaded] = useState&amp;lt;boolean&amp;gt;(false);
  return (
    &amp;lt;View style={{ height: isAdLoaded ? 'auto' : 0 }}&amp;gt;
      &amp;lt;BannerAd
        // It is extremely important to use test IDs as you can be banned/restricted by Google AdMob for inappropriately using real ad banners during testing
        unitId={__DEV__ ? TestIds.BANNER : productionID}
        size={BannerAdSize.ANCHORED_ADAPTIVE_BANNER}
        requestOptions={{
          requestNonPersonalizedAdsOnly: true, 
          // You can change this setting depending on whether you want to use the permissions tracking we set up in the initializing
        }}
        onAdLoaded={() =&amp;gt; {
          setIsAdLoaded(true);
        }}
      /&amp;gt;
    &amp;lt;/View &amp;gt;
  );
};

export default InlineAd;

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

&lt;/div&gt;



&lt;p&gt;Now you can insert &lt;code&gt;InlineAd&lt;/code&gt; anywhere in your app &lt;code&gt;&amp;lt;InlineAd /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's how it looks!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo77jtfiy15q7mfv35nhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo77jtfiy15q7mfv35nhp.png" alt="Google AdMob test banner ad" width="337" height="60"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Creating an Interstitial Ad
&lt;/h3&gt;

&lt;p&gt;Interstitial ads are adverts that take up the entire screen and should be used sparingly as they can dissuade users from using your app if they are overused. &lt;/p&gt;

&lt;p&gt;As with the banner ads above, you need to create an interstitial ad for each app and then get the Ad ID in the following format &lt;code&gt;ca-app-pub-12345678910/12345678910&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One of the best way to use interstitial ads is with pagination (i.e.) moving from one page to another. &lt;/p&gt;

&lt;p&gt;Below, I will update an existing pagination function to show interstitial ads whenever the user moves to the next page or the previous page.&lt;/p&gt;

&lt;p&gt;First, create your &lt;code&gt;Pagination.tsx&lt;/code&gt; or &lt;code&gt;Pagination.jsx&lt;/code&gt; file. Then, prepare your interstitial Ad IDs. Next, prepare an ad request with keywords or personalized ads.&lt;/p&gt;

&lt;p&gt;Then, inside the component itself, use useEffect to load/unload the actual interstitial ad.&lt;/p&gt;

&lt;p&gt;The code below prepares the interstitial ad and only shows it (using &lt;code&gt;interstitial.show();&lt;/code&gt;)  if an ad is loaded and the button is clicked. Sometimes there are no ads available, or the user is offline, so we don't want to cause an accidental error. &lt;/p&gt;

&lt;p&gt;We also use the &lt;code&gt;unsubscribeClosed&lt;/code&gt; to set the &lt;code&gt;loaded&lt;/code&gt; state to false after the interstitial ad has been closed and reload a new ad. This means that no matter how many times a user clicks Previous or Next, there will always be a new ad for them. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Remember, you should put your Ad IDs in environmental variables. The fake IDs below are for display purposes only.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Pagination.tsx

import { AntDesign } from '@expo/vector-icons';
import * as Device from 'expo-device';
import { Link } from 'expo-router';
import React, { useEffect, useState } from 'react';
import { View, Button, Text } from 'react-native';
import { AdEventType, InterstitialAd, TestIds } from 'react-native-google-mobile-ads';

const iosAdmobInterstitial = "ca-app-pub-12345678910/12345678910";
const androidAdmobInterstitial = "ca-app-pub-12345678910/12345678910";
const productionID = Device.osName === 'Android' ? androidAdmobInterstitial : iosAdmobInterstitial;
const adUnitId = __DEV__ ? TestIds.INTERSTITIAL : productionID;
// Make sure to always use a test ID when not in production 


const interstitial = InterstitialAd.createForAdRequest(adUnitId, {
  keywords: ['food', 'cooking', 'fruit'], // Update based on the most relevant keywords for your app/users, these are just random examples
  requestNonPersonalizedAdsOnly: true, // Update based on the initial tracking settings from initialization earlier
});


const Pagination = ({ }) =&amp;gt; {

  const [loaded, setLoaded] = useState&amp;lt;boolean&amp;gt;(false);

  useEffect(() =&amp;gt; {
    // Event listener for when the ad is loaded
    const unsubscribeLoaded = interstitial.addAdEventListener(AdEventType.LOADED, () =&amp;gt; {
      setLoaded(true);
    });

    // Event listener for when the ad is closed
    const unsubscribeClosed = interstitial.addAdEventListener(AdEventType.CLOSED, () =&amp;gt; {
      setLoaded(false);

      // Load a new ad when the current ad is closed
      interstitial.load();
    });

    // Start loading the interstitial ad straight away
    interstitial.load();

    // Unsubscribe from events on unmount
    return () =&amp;gt; {
      unsubscribeLoaded();
      unsubscribeClosed();
    };
  }, []);


  return (
    &amp;lt;View
      style={{
        width: '100%',
        flexDirection: 'row',
        justifyContent: 'space-evenly',
        alignItems: 'center',
        marginVertical: 8,
        paddingHorizontal: 10,
      }}&amp;gt;

        &amp;lt;Link asChild href="/previous-page"&amp;gt;
          &amp;lt;Button onPress={() =&amp;gt; {
            if (loaded) { interstitial.show(); }
          }}&amp;gt;
            &amp;lt;&amp;gt;
              &amp;lt;AntDesign name="arrowleft" size={24} color="#fdb833" /&amp;gt;
              &amp;lt;Text&amp;gt;
                Previous
              &amp;lt;/Text&amp;gt;
            &amp;lt;/&amp;gt;
          &amp;lt;/Button&amp;gt;
        &amp;lt;/Link&amp;gt;



        &amp;lt;Link asChild href="/next-page"&amp;gt;
          &amp;lt;Button onPress={() =&amp;gt; {
            if (loaded) { interstitial.show(); }
          }}&amp;gt;
            &amp;lt;&amp;gt;
              &amp;lt;Text&amp;gt;
                Next
              &amp;lt;/Text&amp;gt;
              &amp;lt;AntDesign name="arrowright" size={24} color="#fdb833" /&amp;gt;
            &amp;lt;/&amp;gt;
          &amp;lt;/Button&amp;gt;
        &amp;lt;/Link&amp;gt;

    &amp;lt;/View&amp;gt;
  );
};

export default Pagination;

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

&lt;/div&gt;



&lt;p&gt;Now you will have functioning interstitial ads on your app!&lt;/p&gt;

&lt;p&gt;Here's how it will look:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqprdjb0ekvc6cej1ui7e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqprdjb0ekvc6cej1ui7e.png" alt="Google AdMob test interstitial ad" width="341" height="671"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After following the steps above, you should be able to see test ads in your app. However, if you want to show ads on a production level app, you need to take some additional steps.&lt;/p&gt;




&lt;h3&gt;
  
  
  Configure Ads for Production
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;app.json&lt;/code&gt;/&lt;code&gt;app.config.js&lt;/code&gt; add the below to the &lt;code&gt;react-native-google-mobile-ads&lt;/code&gt; section. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;user_tracking_usage_description&lt;/code&gt; will display to users to provide informed consent.&lt;br&gt;
&lt;code&gt;sk_ad_network_items&lt;/code&gt; includes all of the SKAdNetwork names to make sure that all of the ad impressions and conversions are tracked for your app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "react-native-google-mobile-ads": {
    "android_app_id": "ca-app-pub-12345678910~123456459",
    "ios_app_id": "ca-app-pub-12345678910~123456459",
    "delay_app_measurement_init": true,
    "user_tracking_usage_description": "This identifier will be used to deliver personalized ads to you.",
    "sk_ad_network_items": [
      "cstr6suwn9.skadnetwork",
      "4fzdc2evr5.skadnetwork",
      "4pfyvq9l8r.skadnetwork",
      "2fnua5tdw4.skadnetwork",
      "ydx93a7ass.skadnetwork",
      "5a6flpkh64.skadnetwork",
      "p78axxw29g.skadnetwork",
      "v72qych5uu.skadnetwork",
      "ludvb6z3bs.skadnetwork",
      "cp8zw746q7.skadnetwork",
      "c6k4g5qg8m.skadnetwork",
      "s39g8k73mm.skadnetwork",
      "3qy4746246.skadnetwork",
      "3sh42y64q3.skadnetwork",
      "f38h382jlk.skadnetwork",
      "hs6bdukanm.skadnetwork",
      "v4nxqhlyqp.skadnetwork",
      "wzmmz9fp6w.skadnetwork",
      "yclnxrl5pm.skadnetwork",
      "t38b2kh725.skadnetwork",
      "7ug5zh24hu.skadnetwork",
      "9rd848q2bz.skadnetwork",
      "y5ghdn5j9k.skadnetwork",
      "n6fk4nfna4.skadnetwork",
      "v9wttpbfk9.skadnetwork",
      "n38lu8286q.skadnetwork",
      "47vhws6wlr.skadnetwork",
      "kbd757ywx3.skadnetwork",
      "9t245vhmpl.skadnetwork",
      "a2p9lx4jpn.skadnetwork",
      "22mmun2rn5.skadnetwork",
      "4468km3ulz.skadnetwork",
      "2u9pt9hc89.skadnetwork",
      "8s468mfl3y.skadnetwork",
      "av6w8kgt66.skadnetwork",
      "klf5c3l5u5.skadnetwork",
      "ppxm28t8ap.skadnetwork",
      "424m5254lk.skadnetwork",
      "ecpz2srf59.skadnetwork",
      "uw77j35x4d.skadnetwork",
      "mlmmfzh3r3.skadnetwork",
      "578prtvx9j.skadnetwork",
      "4dzt52r2t5.skadnetwork",
      "gta9lk7p23.skadnetwork",
      "e5fvkxwrpn.skadnetwork",
      "8c4e2ghe7u.skadnetwork",
      "zq492l623r.skadnetwork",
      "3rd42ekr43.skadnetwork",
      "3qcr597p9d.skadnetwork",
      "vutu7akeur.skadnetwork",
      "eh6m2bh4zr.skadnetwork",
      "pwa73g5rt2.skadnetwork"
    ]
  }
}

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

&lt;/div&gt;



&lt;p&gt;In the "expo" section of your &lt;code&gt;app.json&lt;/code&gt;/&lt;code&gt;app.config.js&lt;/code&gt;, you also need to add the following to your "android" and "ios" sections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"android": {
    "versionCode": 1,
    "adaptiveIcon": {
      "foregroundImage": "./assets/adaptive-icon.png",
      "backgroundColor": "#FFFFF"
    },
    "package": "com.fakeapp.name",
    "permissions": ["com.google.android.gms.permission.AD_ID"],
    "googleServicesFile": "./google-services.json"
},
  "ios": {
    "buildNumber": "1",
    "supportsTablet": true,
    "infoPlist": {
      "NSUserTrackingUsageDescription": "Allow this app to collect app-related data that can be used for tracking you or your device and deliver personalized ads to you.",
      "SKAdNetworkItems": [
        {
          "SKAdNetworkIdentifier": [
            "cstr6suwn9.skadnetwork",
            "4fzdc2evr5.skadnetwork",
            "4pfyvq9l8r.skadnetwork",
            "2fnua5tdw4.skadnetwork",
            "ydx93a7ass.skadnetwork",
            "5a6flpkh64.skadnetwork",
            "p78axxw29g.skadnetwork",
            "v72qych5uu.skadnetwork",
            "ludvb6z3bs.skadnetwork",
            "cp8zw746q7.skadnetwork",
            "c6k4g5qg8m.skadnetwork",
            "s39g8k73mm.skadnetwork",
            "3qy4746246.skadnetwork",
            "3sh42y64q3.skadnetwork",
            "f38h382jlk.skadnetwork",
            "hs6bdukanm.skadnetwork",
            "v4nxqhlyqp.skadnetwork",
            "wzmmz9fp6w.skadnetwork",
            "yclnxrl5pm.skadnetwork",
            "t38b2kh725.skadnetwork",
            "7ug5zh24hu.skadnetwork",
            "9rd848q2bz.skadnetwork",
            "y5ghdn5j9k.skadnetwork",
            "n6fk4nfna4.skadnetwork",
            "v9wttpbfk9.skadnetwork",
            "n38lu8286q.skadnetwork",
            "47vhws6wlr.skadnetwork",
            "kbd757ywx3.skadnetwork",
            "9t245vhmpl.skadnetwork",
            "a2p9lx4jpn.skadnetwork",
            "22mmun2rn5.skadnetwork",
            "4468km3ulz.skadnetwork",
            "2u9pt9hc89.skadnetwork",
            "8s468mfl3y.skadnetwork",
            "av6w8kgt66.skadnetwork",
            "klf5c3l5u5.skadnetwork",
            "ppxm28t8ap.skadnetwork",
            "424m5254lk.skadnetwork",
            "ecpz2srf59.skadnetwork",
            "uw77j35x4d.skadnetwork",
            "mlmmfzh3r3.skadnetwork",
            "578prtvx9j.skadnetwork",
            "4dzt52r2t5.skadnetwork",
            "gta9lk7p23.skadnetwork",
            "e5fvkxwrpn.skadnetwork",
            "8c4e2ghe7u.skadnetwork",
            "zq492l623r.skadnetwork",
            "3rd42ekr43.skadnetwork",
            "3qcr597p9d.skadnetwork",
            "vutu7akeur.skadnetwork",
            "eh6m2bh4zr.skadnetwork",
            "pwa73g5rt2.skadnetwork"
          ]
        }
      ]
    },
    "bundleIdentifier": "com.fakeapp"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need to all the following plugins for transparency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"expo": {
  ...
  plugins: [
      [
        'expo-tracking-transparency',
        {
          userTrackingPermission:
            'Allow this app to collect app-related data that can be used for tracking you or your device and deliver personalized ads to you.',
        },
      ],
      [
        'expo-build-properties',
        {
          ios: {
            useFrameworks: 'static',
          },
          android: {
            extraProguardRules: '-keep class com.google.android.gms.internal.consent_sdk.** { *; }',
          },
        },
      ],
    ],
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Common Problems with Google AdMob for Expo/React Native
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. My ads are showing during testing but not in production
&lt;/h4&gt;

&lt;p&gt;Usually this means that your App IDs or your Ad IDs are configured incorrectly. Make sure that you have added the correct ones. &lt;/p&gt;

&lt;p&gt;Note: if you are using environmental variables with Expo &lt;code&gt;eas build&lt;/code&gt;, you need to include the variables in the &lt;code&gt;eas.json&lt;/code&gt; and also submit the secrets on the Expo website.&lt;/p&gt;

&lt;h5&gt;
  
  
  2. My ads are showing perfectly but I am not getting any impressions on the AdMob dashboard
&lt;/h5&gt;

&lt;p&gt;Sometimes it take can take a few days for new apps to start registering ads correctly on the dashboard. Make sure that all of your configurations and verifications on the AdMob dashboard are completed properly.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. My ads are only showing impressions for one of my apps on the AdMob dashboard
&lt;/h4&gt;

&lt;p&gt;This problem is usually caused by accidentally using the same Ad ID for both iOS and Android. Double check that each device type is using its own Ad ID. (i.e. &lt;code&gt;Device.osName === 'Android' ? androidAdmobInterstitialId : iosAdmobInterstitialId;&lt;/code&gt; )&lt;/p&gt;




&lt;p&gt;Thanks for following along with this tutorial for adding Google AdMob to Expo devices! If you're interested in learning more about me, you can visit my portfolio &lt;a href="https://josiedaw.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are facing an error anywhere along the way that is not one of the common problems I've already answered, feel free to leave a comment below and we can try to debug it together!&lt;/p&gt;

</description>
      <category>expo</category>
      <category>admob</category>
      <category>monetization</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
