Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(video): add support for video ad volume control #613

Merged
merged 4 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions __tests__/googleMobileAds.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ describe('Admob', function () {
admob().openDebugMenu('');
}).toThrowError('openDebugMenu expected a non-empty string value');
});

it('does call native setAppVolume method', () => {
admob().setAppVolume(0.5);
expect(RNGoogleMobileAdsModule.setAppVolume).toBeCalledTimes(1);
});

it('throws if setAppVolume is greater than 1', function () {
expect(() => {
admob().setAppVolume(2);
}).toThrowError('The app volume must be a value between 0 and 1 inclusive.');
});

it('does call native setAppMuted method', () => {
admob().setAppMuted(true);
expect(RNGoogleMobileAdsModule.setAppMuted).toBeCalledTimes(1);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,14 @@ public void openDebugMenu(final String adUnit) {
.runOnUiThread(() -> MobileAds.openDebugMenu(getCurrentActivity(), adUnit));
}
}

@ReactMethod
public void setAppVolume(final Float volume) {
MobileAds.setAppVolume(volume);
}

@ReactMethod
public void setAppMuted(final Boolean muted) {
MobileAds.setAppMuted(muted);
}
}
3 changes: 2 additions & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
["Displaying Ads via Hook", "/displaying-ads-hook"],
["European User Consent", "/european-user-consent"],
["Ad Inspector", "/ad-inspector"],
["Impression-level ad revenue", "/impression-level-ad-revenue"]
["Impression-level ad revenue", "/impression-level-ad-revenue"],
["Video ad volume control", "/video-ad_volume-control"]
]
],
[
Expand Down
49 changes: 49 additions & 0 deletions docs/video-ad_volume-control.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Video ad volume control

<Info>
Video volume controls apply only to Google ads and are not forwarded to mediation networks.
</Info>

If your app has its own volume controls, such as custom music or sound effect volumes, disclosing app volume to the Google Mobile Ads SDK enables video ads to respect app volume settings. This ensures users receive video ads with the expected audio volume.

The device volume, controlled through volume buttons or OS-level volume slider, determines the volume for device audio output. However, apps can independently adjust volume levels relative to the device volume to tailor the audio experience.

For App Open, Banner, Interstitial, Rewarded, and Rewarded Interstitial ad formats you can report the relative app volume to the Google Mobile Ads SDK by calling the `setAppVolume` function. Valid ad volume values range from `0.0` (silent) to `1.0` (current device volume). Here's an example of how to report the relative app volume to the SDK:

```js
import React from 'react';
import MobileAds, { GAMBannerAd, BannerAdSize, TestIds } from 'react-native-google-mobile-ads';

const adUnitId = __DEV__ ? TestIds.GAM_BANNER : '/xxx/yyyy';

function App() {
MobileAds().setAppVolume(0.5);

return <GAMBannerAd unitId={adUnitId} sizes={[BannerAdSize.FULL_BANNER]} />;
}
```

<Error>
Lowering your app's audio volume reduces video ad eligibility and might reduce your app's ad revenue. You should only utilize this API if your app provides custom volume controls to the user, and the user's volume is properly reflected in the API.
</Error>

For App Open, Banner, Interstitial, Rewarded, and Rewarded Interstitial ad formats, you can inform the Google Mobile Ads SDK that the app volume has been muted by calling the `setAppMuted` function:

```js
import React from 'react';
import MobileAds, { GAMBannerAd, BannerAdSize, TestIds } from 'react-native-google-mobile-ads';

const adUnitId = __DEV__ ? TestIds.GAM_BANNER : '/xxx/yyyy';

function App() {
MobileAds().setAppMuted(true);

return <GAMBannerAd unitId={adUnitId} sizes={[BannerAdSize.FULL_BANNER]} />;
}
```

By default, `appVolume` is set to 1 (the current device volume) and `appMuted` is set to `NO`.

<Error>
Muting your app reduces video ad eligibility and might reduce your app's ad revenue. You should only utilize this API if your app provides a custom mute control to the user, and the user's mute decision is properly reflected in the API.
</Error>
12 changes: 12 additions & 0 deletions ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ - (dispatch_queue_t)methodQueue {
#endif
}

RCT_EXPORT_METHOD(setAppVolume : (float)volume) {
#if !TARGET_OS_MACCATALYST
GADMobileAds.sharedInstance.applicationVolume = volume;
#endif
}

RCT_EXPORT_METHOD(setAppMuted : (BOOL *)muted) {
#if !TARGET_OS_MACCATALYST
GADMobileAds.sharedInstance.applicationMuted = muted;
#endif
}

#ifdef RCT_NEW_ARCH_ENABLED
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params {
Expand Down
2 changes: 2 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jest.doMock('react-native', () => {
setRequestConfiguration: jest.fn(),
openAdInspector: jest.fn(),
openDebugMenu: jest.fn(),
setAppVolume: jest.fn(),
setAppMuted: jest.fn(),
};
},
},
Expand Down
10 changes: 10 additions & 0 deletions src/MobileAds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ class MobileAdsModule implements MobileAdsModuleInterface {
if (!adUnit) throw new Error('googleMobileAds.openDebugMenu expected a non-empty string value');
RNGoogleMobileAdsModule.openDebugMenu(adUnit);
}

setAppVolume(volume: number) {
if (volume < 0 || volume > 1)
throw new Error('The app volume must be a value between 0 and 1 inclusive.');
RNGoogleMobileAdsModule.setAppVolume(volume);
}

setAppMuted(muted: boolean) {
RNGoogleMobileAdsModule.setAppMuted(muted);
}
}

const MobileAdsInstance = new MobileAdsModule();
Expand Down
2 changes: 2 additions & 0 deletions src/NativeGoogleMobileAdsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export interface Spec extends TurboModule {
setRequestConfiguration(requestConfiguration?: UnsafeObject): Promise<void>;
openAdInspector(): Promise<void>;
openDebugMenu(adUnit: string): void;
setAppVolume(volume: number): void;
setAppMuted(muted: boolean): void;
}

export default TurboModuleRegistry.getEnforcing<Spec>('RNGoogleMobileAdsModule');
28 changes: 28 additions & 0 deletions src/types/MobileAdsModule.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,32 @@ export interface MobileAdsModuleInterface {
* @param adUnit Any valid ad unit from your Ad Manager account is sufficient to open the debug options menu.
*/
openDebugMenu(adUnit: string): void;

/**
* Sets the application's audio volume. Affects audio volumes of all ads relative to other audio output.
*
* Warning: Lowering your app's audio volume reduces video ad eligibility and may reduce your app's ad revenue.
* You should only utilize this API if your app provides custom volume controls to the user, and you should reflect
* the user's volume choice in this API.
*
* @see https://developers.google.com/ad-manager/mobile-ads-sdk/android/global-settings
* @see https://developers.google.com/ad-manager/mobile-ads-sdk/ios/global-settings
*
* @param volume the volume as a float from 0 (muted) to 1.0 (full media volume). Defaults to 1.0
*/
setAppVolume(volume: number): void;

/**
* Indicates whether the application's audio is muted. Affects initial mute state for all ads.
*
* Warning: Muting your application reduces video ad eligibility and may reduce your app's ad revenue.
* You should only utilize this API if your app provides a custom mute control to the user, and you should
* reflect the user's mute decision in this API.
*
* @see https://developers.google.com/ad-manager/mobile-ads-sdk/android/global-settings
* @see https://developers.google.com/ad-manager/mobile-ads-sdk/ios/global-settings
*
* @param muted true if the app is muted, false otherwise. Defaults to false.
*/
setAppMuted(muted: boolean): void;
}
Loading